[
  {
    "path": ".azuredevops/dependabot.yml",
    "content": "version: 2\r\n\r\n# Disabling dependabot on Azure DevOps as this is a mirrored repo. Updates should go through github.\r\nenable-campaigned-updates: false\r\nenable-security-updates: false\r\n"
  },
  {
    "path": ".config/1espt/PipelineAutobaseliningConfig.yml",
    "content": "## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.\n\npipelines:\n  1190:\n    retail:\n      source:\n        credscan:\n          lastModifiedDate: 2024-03-28\n        eslint:\n          lastModifiedDate: 2024-03-28\n        psscriptanalyzer:\n          lastModifiedDate: 2024-03-28\n        armory:\n          lastModifiedDate: 2024-03-28\n      binary:\n        credscan:\n          lastModifiedDate: 2024-03-28\n        binskim:\n          lastModifiedDate: 2025-03-19\n        spotbugs:\n          lastModifiedDate: 2024-03-28\n"
  },
  {
    "path": ".config/1espt/README.md",
    "content": "Do not merge changes to PipelineAutobaseliningConfig.yml in the internal Azure DevOps repository, as it would break commit mirroring from the public GitHub repository.  Instead, merge the changes into the public GitHub repository.\n\nSee https://dev.azure.com/dnceng/internal/_wiki/wikis/DNCEng%20Services%20Wiki/1214/1ES-Pipeline-Template-Migration-FAQ?anchor=should-i-accept-these-automated-prs-into-my-repo-that-is-mirrored-from-github-to-fix-cg/security-issues%3F for guidance."
  },
  {
    "path": ".editorconfig",
    "content": "﻿root = true\n\n[*]\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\n\n[*.{csproj,md,props,targets,yml}]\nindent_size = 2\n\n[*.cs]\n\n# IDE0063: Use simple 'using' statement\ncsharp_prefer_simple_using_statement = false\n\n# CA2254: Template should be a static expression\n# See https://github.com/dotnet/roslyn-analyzers/issues/5626\ndotnet_diagnostic.CA2254.severity = none\n\n# CA2255: The ModuleInitializer attribute should not be used in libraries\ndotnet_diagnostic.CA2255.severity = none\n\n# IDE0073: File header\ndotnet_diagnostic.IDE0073.severity = warning\nfile_header_template = Licensed to the .NET Foundation under one or more agreements.\\nThe .NET Foundation licenses this file to you under the MIT license.\\nSee the LICENSE.txt file in the project root for more information.\n"
  },
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# These owners will be the default owners for everything in\n# the repo. Unless a later match takes precedence,\n# review when someone opens a pull request.\n# For more on how to customize the CODEOWNERS file - https://help.github.com/en/articles/about-code-owners\n*       @dotnet/sign-maintainers\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**Repro steps**\n<!--\nPoint us to a minimalistic repro hosted in a GitHub repo, Gist snippet, or elsewhere to see the isolated behavior.\nWe may close this issue if we are unable to reproduce the behavior you're reporting.\n-->\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Actual behavior**\nA clear and concise description of what actually happened.\n\n**Additional context**\n- Include the output of `sign --version`.\n- Include the output of `dotnet --info`.\n- Add any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nInclude the output of sign --version.\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: 'Close stale issues'\n\npermissions:\n  issues: write\n\non:\n  schedule:\n    - cron: '30 1 * * *'\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v9\n        with:\n          stale-issue-message: 'This issue is stale because it has been open 10 days with no activity after asking for more info. Comment or this will be closed in 4 days.'\n          close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity. This can be reopened if additional information is provided.'\n          days-before-issue-stale: 10          \n          days-before-issue-close: 4\n          days-before-pr-stale: -1\n          days-before-pr-close: -1\n          any-of-labels: \"needs-more-info\"\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# Tools directory\n.dotnet/\n.packages/\n.tools/\n/[Tt]ools/\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\n[Xx]64/\n[Xx]86/\n[Bb]uild/\nbld/\n[Bb]in/\n[Oo]bj/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n.vscode/\n.store/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\n*.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n\n# TODO: Un-comment the next line if you do not want to checkin \n# your web deploy settings because they may include unencrypted\n# passwords\n#*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Microsoft Azure ApplicationInsights config file\nApplicationInsights.config\n\n# Windows Store app package directory\nAppPackages/\nBundleArtifacts/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# LightSwitch generated files\nGeneratedArtifacts/\nModelManifest.xml\n\n# Paket dependency manager\n.paket/paket.exe\n\n# FAKE - F# Make\n.fake/\n/src/SignClient/Properties/launchSettings.json\n/src/SignService/Properties/launchSettings.json\n/src/SignService/App_Data/\n\n/src/SignService/tools/SDK/\n!**/KeyVaultSignToolWrapper/x86/\n!**/KeyVaultSignToolWrapper/x64/\n/src/SignService/Properties/PublishProfiles\n/src/InstallUtility/Properties/launchSettings.json\n/arm/ArmDeploy/azuredeploy.parameters.json\n"
  },
  {
    "path": ".vsts-ci.yml",
    "content": "# Pipeline: https://dnceng.visualstudio.com/internal/_build?definitionId=1190\n\nvariables:\n  - name: _TeamName\n    value: DotNetCore\n  - name: Build.Repository.Clean\n    value: true\n  - name: Codeql.Enabled\n    value: true\n  - name: Codeql.TSAEnabled\n    value: true\n  - group: DotNet-Sign-SDLValidation-Params\n  - template: /eng/common/templates-official/variables/pool-providers.yml\n\ntrigger:\n  batch: true\n  branches:\n    include:\n    - main\n  paths:\n    exclude:\n    - \"*.md\"\n\npr:\n  autoCancel: false\n  branches:\n    include:\n    - '*'\n\nresources:\n  repositories:\n  - repository: 1esPipelines\n    type: git\n    name: 1ESPipelineTemplates/1ESPipelineTemplates\n    ref: refs/tags/release\n\nextends:\n  template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines\n  parameters:\n    settings:\n      networkIsolationPolicy: Permissive,CFSClean,CFSClean2\n    sdl:\n      sourceAnalysisPool:\n        name: $(DncEngInternalBuildPool)\n        image: 1es-windows-2022\n        os: windows\n    customBuildTags:\n    - ES365AIMigrationTooling\n    stages:\n    - stage: Build_Windows\n      displayName: Build Windows\n      jobs:\n      - ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}:\n        - template: /eng/common/templates-official/job/onelocbuild.yml@self\n          parameters:\n            LclSource: lclFilesfromPackage\n            LclPackageId: 'LCL-JUNO-PROD-SIGNCLI'\n            MirrorRepo: sign\n\n      - template: /eng/common/templates-official/jobs/jobs.yml@self\n        parameters:\n          enableMicrobuild: true\n          enablePublishBuildArtifacts: true\n          enablePublishBuildAssets: true\n          enablePublishUsingPipelines: true\n          enableTelemetry: true\n          jobs:\n          - job: Windows\n            pool: # See https://helix.dot.net/ for VM names.\n              name: NetCore1ESPool-Internal\n              demands: ImageOverride -equals windows.vs2022.amd64\n            variables:\n            # Only enable publishing in official builds.\n            - ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n              # Publish-Build-Assets provides: MaestroAccessToken, BotAccount-dotnet-maestro-bot-PAT\n              - group: Publish-Build-Assets\n              - name: _SignType\n                value: real\n              - name: _OfficialBuildArgs\n                value: /p:DotNetPublishUsingPipelines=true\n                      /p:DotNetSignType=$(_SignType)\n                      /p:OfficialBuildId=$(BUILD.BUILDNUMBER)\n                      /p:TeamName=$(_TeamName)\n            - ${{ else }}:\n              - name: _SignType\n                value: test\n              - name: _OfficialBuildArgs\n                value: ''\n            strategy:\n              matrix:\n                Release:\n                  _BuildConfig: Release\n            steps:\n            - task: CodeQL3000Init@0\n              displayName: Initialize CodeQL\n              condition: and(succeeded(), eq(variables['Codeql.Enabled'], 'true'))\n            - script: eng\\common\\CIBuild.cmd\n                -configuration $(_BuildConfig)\n                -prepareMachine\n                $(_OfficialBuildArgs)\n              name: Build\n              displayName: Build and run tests\n              condition: succeeded()\n            - task: CodeQL3000Finalize@0\n              displayName: Finalize CodeQL\n              condition: and(succeeded(), eq(variables['Codeql.Enabled'], 'true'))\n            # Guardian requires npm.\n            - task: NodeTool@0\n              inputs:\n                versionSpec: '18.x'\n            # Validates compiler/linker settings and other security-related binary characteristics.\n            # https://github.com/Microsoft/binskim\n            # YAML reference: https://eng.ms/docs/security-compliance-identity-and-management-scim/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/sdl-azdo-extension/binskim-build-task#v4\n            - task: BinSkim@4\n              displayName: Run BinSkim\n              inputs:\n                InputType: Basic\n                Function: analyze\n                TargetPattern: binskimPattern\n                AnalyzeTargetBinskim: $(Build.SourcesDirectory)\\artifacts\\bin\\Sign.Cli\\$(_BuildConfig)\\net8.0\\publish\\*.dll\n                AnalyzeSymPath: 'SRV*https://symweb'\n              condition: succeededOrFailed()\n            - task: PublishTestResults@2\n              displayName: 'Publish Unit Test Results'\n              inputs:\n                testResultsFormat: xUnit\n                testResultsFiles: '$(Build.SourcesDirectory)/artifacts/TestResults/**/*.xml'\n                mergeTestResults: true\n                searchFolder: $(System.DefaultWorkingDirectory)\n                testRunTitle: sign unit tests - $(Agent.JobName)\n              condition: succeededOrFailed()\n            - task: ComponentGovernanceComponentDetection@0\n              displayName: Component Governance scan\n              inputs:\n                ignoreDirectories: '$(Build.SourcesDirectory)/.packages,$(Build.SourcesDirectory)/artifacts/obj/Sign.Cli'\n\n    - template: /eng/common/templates-official/post-build/post-build.yml@self\n      parameters:\n        publishingInfraVersion: 3\n        enableSymbolValidation: true\n        enableSourceLinkValidation: true\n        validateDependsOn:\n        - Build_Windows\n        publishDependsOn:\n        - Validate\n        # This is to enable SDL runs part of Post-Build Validation Stage\n        SDLValidationParameters:\n          enable: true\n          params: ' -SourceToolsList @(\"policheck\",\"credscan\")\n          -TsaInstanceURL $(_TsaInstanceURL)\n          -TsaProjectName $(_TsaProjectName)\n          -TsaNotificationEmail $(_TsaNotificationEmail)\n          -TsaCodebaseAdmin $(_TsaCodebaseAdmin)\n          -TsaBugAreaPath $(_TsaBugAreaPath)\n          -TsaIterationPath $(_TsaIterationPath)\n          -TsaRepositoryName dotnet-sign\n          -TsaCodebaseName dotnet-sign\n          -TsaOnboard $True\n          -TsaPublish $True\n          -PoliCheckAdditionalRunConfigParams @(\"UserExclusionPath < $(Build.SourcesDirectory)/eng/PoliCheckExclusions.xml\")'"
  },
  {
    "path": ".vsts-pr.yml",
    "content": "# Pipeline: https://dev.azure.com/dnceng-public/public/_build?definitionId=231\n\nvariables:\n  - name: _TeamName\n    value: DotNetCore\n  - name: Build.Repository.Clean\n    value: true\n\ntrigger:\n  batch: true\n  branches:\n    include:\n    - main\n  paths:\n    exclude:\n    - \"*.md\"\n\nstages:\n- stage: Build_Windows\n  displayName: Build Windows\n  jobs:\n  - template: /eng/common/templates/jobs/jobs.yml\n    parameters:\n      enableMicrobuild: true\n      jobs:\n      - job: Windows\n        pool: # See https://helix.dot.net/ for VM names.\n          name: NetCore-Public\n          demands: ImageOverride -equals windows.vs2022.amd64.open\n        variables:\n          - name: _SignType\n            value: test\n        strategy:\n          matrix:\n            Release:\n              _BuildConfig: Release\n        steps:\n        - script: eng\\common\\CIBuild.cmd\n            -configuration $(_BuildConfig)\n            -prepareMachine\n          name: Build\n          displayName: Build and run tests\n          condition: succeeded()\n        - task: PublishTestResults@2\n          displayName: 'Publish test results'\n          inputs:\n            testResultsFormat: xUnit\n            testResultsFiles: '$(Build.SourcesDirectory)/artifacts/TestResults/**/*.xml'\n            mergeTestResults: true\n            searchFolder: $(System.DefaultWorkingDirectory)\n            testRunTitle: sign unit tests - $(Agent.JobName)\n          condition: succeededOrFailed()\n        - task: PublishBuildArtifacts@1\n          displayName: 'Publish log files on failure'\n          inputs:\n            PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'\n            ArtifactName: 'Logs'\n            publishLocation: 'Container'\n          condition: failed()\n"
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "content": "# Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant\nto clarify expected behavior in our community.\n\nFor more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.DotNet.Arcade.Sdk\" />\n\n  <PropertyGroup>\n    <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>\n    <Copyright>$(CopyrightNetFoundation)</Copyright>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>embedded</DebugType>\n    <Deterministic>true</Deterministic>\n    <EnableXlfLocalization>true</EnableXlfLocalization>\n    <Features>strict</Features>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <!--\n      Tools and packages produced by this repository support infrastructure and are not shipping on NuGet or via any other official channel.\n      This default is overridden in shipping projects.\n    -->\n    <IsShipping>false</IsShipping>\n    <LangVersion>Latest</LangVersion>\n    <!-- CS8002:  some dependencies are not strong name signed. -->\n    <NoWarn>CS8002</NoWarn>\n    <Nullable>enable</Nullable>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <TargetFramework>net8.0</TargetFramework>\n    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>\n    <UpdateXlfOnBuild Condition=\"'$(CI)' != '1'\">true</UpdateXlfOnBuild>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <UseAppHost>false</UseAppHost>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RepositoryRootDirectory>$(MSBuildThisFileDirectory)</RepositoryRootDirectory>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" PublicKey=\"0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Directory.Build.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"Sdk.targets\" Sdk=\"Microsoft.DotNet.Arcade.Sdk\" />\n</Project>"
  },
  {
    "path": "Directory.Packages.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageVersion Include=\"Azure.CodeSigning.Sdk\" Version=\"0.1.164\" />\n    <PackageVersion Include=\"Azure.Core\" Version=\"1.54.0\" />\n    <PackageVersion Include=\"Azure.Identity\" Version=\"1.21.0\" />\n    <PackageVersion Include=\"Azure.Security.KeyVault.Certificates\" Version=\"4.8.0\" />\n    <PackageVersion Include=\"Azure.Security.KeyVault.Keys\" Version=\"4.9.0\" />\n    <PackageVersion Include=\"AzureSign.Core\" Version=\"7.0.1\" />\n    <PackageVersion Include=\"coverlet.collector\" Version=\"10.0.0\" />\n    <PackageVersion Include=\"Microsoft.AspNetCore.Server.Kestrel\" Version=\"2.3.9\" />\n    <PackageVersion Include=\"Microsoft.Dynamics.BusinessCentral.Sip.Main\" Version=\"24.0.15760\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Azure\" Version=\"1.14.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.EnvironmentVariables\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.Json\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"Microsoft.Extensions.FileSystemGlobbing\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging.Console\" Version=\"10.0.7\" />\n    <!-- Only use release versions.  Pre-release versions are signed with an untrusted certificate. -->\n    <PackageVersion Include=\"Microsoft.Windows.SDK.BuildTools\" Version=\"10.0.28000.1721\" />\n    <!-- We're staying on 4.18.4 until we migrate to another mocking framework.\n         See https://github.com/dotnet/runtime/issues/90222 and https://github.com/devlooped/moq/issues/1374\n         for context.   -->\n    <PackageVersion Include=\"Moq\" Version=\"4.18.4\" />\n    <PackageVersion Include=\"NuGet.Packaging\" Version=\"7.3.1\" />\n    <PackageVersion Include=\"NuGet.Protocol\" Version=\"7.3.1\" />\n    <PackageVersion Include=\"System.CommandLine\" Version=\"2.0.7\" />\n    <PackageVersion Include=\"System.Security.Cryptography.Pkcs\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"System.Security.Cryptography.Xml\" Version=\"10.0.7\" />\n    <PackageVersion Include=\"System.Text.Json\" Version=\"10.0.7\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) .NET Foundation and Contributors\n\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "NuGet.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <add key=\"dotnet-eng\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json\" />\n    <add key=\"dotnet-public\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json\" />\n    <add key=\"dotnet-tools\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json\" />\n  </packageSources>\n  <packageSourceMapping>\n    <clear />\n    <packageSource key=\"dotnet-eng\">\n      <package pattern=\"MicroBuild.Core.Sentinel\" />\n      <package pattern=\"Microsoft.*\" />\n    </packageSource>\n    <packageSource key=\"dotnet-public\">\n      <package pattern=\"Azure.*\" />\n      <package pattern=\"AzureSign.Core\" />\n      <!-- Used by Arcade -->\n      <package pattern=\"binlogtool\" />\n      <package pattern=\"Castle.Core\" />\n      <package pattern=\"coverlet.collector\" />\n      <package pattern=\"MicroBuild.Core\" />\n      <package pattern=\"Microsoft.*\" />\n      <package pattern=\"Moq\" />\n      <package pattern=\"Newtonsoft.Json\" />\n      <package pattern=\"NuGet.*\" />\n      <!-- Used by Arcade -->\n      <package pattern=\"sourcelink\" />\n      <package pattern=\"System.*\" />\n      <package pattern=\"vswhere\" />\n      <package pattern=\"xunit.*\" />\n    </packageSource>\n    <packageSource key=\"dotnet-tools\">\n      <package pattern=\"sn\" />\n    </packageSource>\n  </packageSourceMapping>\n  <disabledPackageSources>\n    <clear />\n  </disabledPackageSources>\n</configuration>\n"
  },
  {
    "path": "README.md",
    "content": "# Sign CLI\n\n[<img align=\"right\" src=\"https://xunit.net/images/dotnet-fdn-logo.png\" width=\"100\" />](https://www.dotnetfoundation.org/)\n\nThis project aims to make it easier to integrate secure code signing into a CI pipeline by using cloud-based hardware security module(HSM)-protected keys. This project is part of the [.NET Foundation](https://www.dotnetfoundation.org/) and operates under their [code of conduct](https://www.dotnetfoundation.org/code-of-conduct). It is licensed under [MIT](https://opensource.org/licenses/MIT) (an OSI approved license).\n\nYou can find the latest version of Sign CLI on [NuGet.org](https://www.nuget.org/packages/sign).\n\n## Prerequisites\n\n- An up-to-date x64-based version of Windows currently in [mainstream support](https://learn.microsoft.com/lifecycle/products/)\n- [.NET 8 SDK or later](https://dotnet.microsoft.com/download)\n- [Microsoft Visual C++ 14 runtime](https://aka.ms/vs/17/release/vc_redist.x64.exe)\n\n## Install\n\nTo install Sign CLI in the current directory, open a command prompt and execute:\n\n```\ndotnet tool install --tool-path . --prerelease sign\n```\n\nTo run Sign CLI, execute `sign` from the same directory.\n\n## Design\n\nGiven an initial file path or glob pattern, this tool recursively searches directories and containers to find signable files and containers.  For each signable artifact, the tool uses an implementation of [`System.Security.Cryptography.RSA`](https://learn.microsoft.com/dotnet/api/system.security.cryptography.rsa?view=net-8.0) that delegates the signing operation to Azure Key Vault.  The tool computes a digest (or hash) of the to-be-signed content and submits the digest --- not the original content --- to Azure Key Vault for digest signing.  The returned raw signature value is then incorporated in whatever signature format is appropriate for the file type.  Signable content is not sent to Azure Key Vault.\n\nWhile the current version is limited to RSA and Azure Key Vault, it is desirable to support ECDSA and other cloud providers in the future.\n\n## Supported File Types\n\n- `.msi`, `.msp`, `.msm`, `.cab`, `.dll`, `.exe`, `.appx`, `.appxbundle`, `.msix`, `.msixbundle`, `.sys`, `.vxd`, `.ps1`, `.psm1`, and any portable executable (PE) file (via [AzureSignTool](https://github.com/vcsjones/AzureSignTool))\n- `.vsix`\n- ClickOnce `.application` and `.vsto` (via `Mage`). Notes below.\n- `.nupkg`\n\n## ClickOnce\nThere are a couple of possibilities for signing ClickOnce packages.\n\nGenerally you will want to sign an entire package and all its contents i.e. the deployment manifest (`.application` or `.vsto`),\napplication manifest (`.exe.manifest` or `.dll.manifest`) and the underlying `.exe` and `.dll` files themselves.\nTo do this, ensure that the entire contents of the package are available (i.e. the whole `publish` folder from your build) and pass\nthe deployment manifest as the file to sign - the rest of the files will be detected and signed in the proper order automatically.\n\nYou can also re-sign just the deployment manifest in case you want to e.g. change the Deployment URL but leave the rest of the contents the\nsame. To do this, pass the deployment manifest as the file to sign as in the case above, but just don't have the rest of the files\npresent on-disk alongside it. This tool will detect that they're missing and just update the signature on the deployment manifest.\nNote that this is strictly for re-signing an already-signed deployment manifest - you cannot have a signed deployment manifest that\npoints to an un-signed application manifest. You must also take care to sign all manifests with the same certificate otherwise the application\nwill not install.\n\nYou should also use the `filter` parameter with the file list to sign, something like this:\n```\n**/ProjectAddIn1.*\n**/setup.exe\n```\n\n## Best Practices\n\n* Create a [ServicePrincipal with minimum permissions](https://learn.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal). Note that you do not need to assign any subscription-level roles to this identity. Only access to Key Vault is required.\n* Follow [Best practices for using Azure Key Vault](https://learn.microsoft.com/azure/key-vault/general/best-practices). The Premium SKU is required for code signing certificates to meet key storage requirements.\n   * If using Azure role-based access control (RBAC), [configure your signing account to have these roles](https://learn.microsoft.com/azure/key-vault/general/rbac-guide?tabs=azure-portal):\n     - Key Vault Reader\n     - Key Vault Crypto User\n   * If using Azure Key Vault access policies, [configure an access policy](https://learn.microsoft.com/azure/key-vault/general/assign-access-policy?tabs=azure-portal) for your signing account to have minimal permissions:\n     - Key permissions\n       - Cryptographic Operations\n         - Sign\n       - Key Management Operations\n         - Get  _(Note:  this is only for the public key not the private key.)_\n     - Certificate permissions\n       - Certificate Management Operations\n         - Get\n* Isolate signing operations in a separate leg of your build pipeline.\n* Ensure that this CLI and all input and output files are in a directory under your control.\n* Execute this CLI as a standard user.  Elevation is not required.\n* Use [OIDC authentication from your GitHub Action to Azure](https://learn.microsoft.com/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect).\n\n## Sample Workflows\n\n* [Azure DevOps Pipelines](./docs/azdo-build-and-sign.yml)\n* [GitHub Actions](./docs/gh-build-and-sign.yml)\n\nCode signing is a complex process that may involve multiple signing formats and artifact types. Some artifacts are containers that contain other signable file types. For example, NuGet Packages (`.nupkg`) frequently contain `.dll` files. The signing tool will sign all files inside-out, starting with the most nested files and then the outer files, ensuring everything is signed in the correct order.\n\nSigning `.exe`/`.dll` files, and other Authenticode file types is only possible on Windows at this time. The recommended solution is to build on one agent and sign on another using jobs or stages where the signing steps run on Windows. Running code signing on a separate stage to ensure secrets aren't exposed to the build stage.\n\n### Build Variables\n\nThe following information is needed for the signing build:\n\n* `Tenant Id` Azure AD tenant\n* `Client Id` / `Application Id` ServicePrincipal identifier\n* `Key Vault Url` Url to Key Vault. Must be a Premium Sku for EV code signing certificates and all certificates issued after June 2023\n* `Certificate Id` Id of the certificate in Key Vault.\n* `Client Secret` for Azure DevOps Pipelines\n* `Subscription Id` for GitHub Actions\n\n## Creating a code signing certificate in Azure Key Vault\n\nCode signing certificates must use the `RSA-HSM` key type to ensure the private keys are stored in a FIPS 140-2 compliant manner. While you can import a certificate from a PFX file, if available, the most secure option is to create a new Certificate Signing Request to provide to your certificate authority, and then merge in the public certificate they issue. Detailed steps are available [here](https://learn.microsoft.com/answers/questions/732422/ev-code-signing-with-azure-keyvault-and-azure-pipe).\n\n## Migrating from the legacy code signing service\n\nIf you've been using the legacy code signing service, using `SignClient.exe` to upload files for signing, you can use your existing certificate and Key Vault with this new tool. You will need to create a new ServicePrincipal and assign it permissions as described above.\n\n## FAQ\n\n### What signature algorithms are supported?\n\nAt this time, only RSA PKCS #1 v1.5 is supported.\n\nECDSA is not supported.  Not only do some signature providers not support ECDSA, [the Microsoft Trusted Root Program does not support ECDSA code signing.](https://learn.microsoft.com/security/trusted-root/program-requirements#b-signature-requirements)\n\n> **Please Note**: Signatures using elliptical curve cryptography (ECC), such as ECDSA, aren't supported in Windows and newer Windows security features. Users utilizing these algorithms and certificates will face various errors and potential security risks. The Microsoft Trusted Root Program recommends that ECC/ECDSA certificates shouldn't be issued to subscribers due to this known incompatibility and risk.\n\n## Useful Links\n\n* [Issue Triage Policy](triage-policy.md)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nMicrosoft serves as the primary maintainer of this repository. If you believe you have found a security vulnerability that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). \n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n  * Full paths of source file(s) related to the manifestation of the issue\n  * The location of the affected source code (tag/branch/commit or direct URL)\n  * Any special configuration required to reproduce the issue\n  * Step-by-step instructions to reproduce the issue\n  * Proof-of-concept or exploit code (if possible)\n  * Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->\n"
  },
  {
    "path": "SdkTools.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Windows.SDK.BuildTools\" IncludeAssets=\"build\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"Microsoft.Dynamics.BusinessCentral.Sip.Main\" GeneratePathProperty=\"true\" ExcludeAssets=\"All\" />\n  </ItemGroup>\n\n  <PropertyGroup>\n    <NetSdkBinDir Condition=\" '$(NetSdkBinDir)' == '' \">$(MSBuildProgramFiles32)\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.8 Tools</NetSdkBinDir>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\appxsip.dll\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\appxpackaging.dll\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\opcservices.dll\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\Microsoft.Windows.Build.Appx.AppxPackaging.dll.manifest\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\Microsoft.Windows.Build.Appx.AppxSip.dll.manifest\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\Microsoft.Windows.Build.Appx.OpcServices.dll.manifest\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\Microsoft.Windows.Build.Signing.mssign32.dll.manifest\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\Microsoft.Windows.Build.Signing.wintrust.dll.manifest\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\makeappx.exe\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\makepri.exe\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\mssign32.dll\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\wintrust.dll\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\wintrust.dll.ini\" />\n    <SdkFile64 Include=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\SignTool.exe.manifest\" />\n    <SdkFile64 Include=\"$(PkgMicrosoft_Dynamics_BusinessCentral_Sip_Main)\\x64\\NavSip.dll\" />\n\n    <SdkFile86 Include=\"$(NetSdkBinDir)\\mage.exe\" />\n  </ItemGroup>\n\n  <Target Name=\"CopySdkFiles\" AfterTargets=\"Build\">\n    <Copy SourceFiles=\"@(SdkFile64)\" DestinationFolder=\"$(OutputPath)\\tools\\SDK\\x64\" SkipUnchangedFiles=\"true\" />\n    <Copy SourceFiles=\"@(SdkFile86)\" DestinationFolder=\"$(OutputPath)\\tools\\SDK\\x86\" SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <Target Name=\"UpdateWintrust\" AfterTargets=\"Build\">\n    <PropertyGroup>\n      <PowerShellFilePath Condition=\" '$(PowerShellFilePath)' == '' \">%WINDIR%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe</PowerShellFilePath>  \n      <ScriptFilePath Condition=\" '$(ScriptFilePath)' == '' \">$(RepositoryRootDirectory)\\scripts\\UpdateWintrust.ps1</ScriptFilePath>\n    </PropertyGroup>\n\n    <Exec Command=\"$(PowerShellFilePath) -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -Command &quot;&amp; { &amp;'$(ScriptFilePath)' '$(OutputPath)tools\\SDK\\x64\\wintrust.dll.ini' } &quot;\" LogStandardErrorAsError=\"true\" />\n  </Target>\n\n  <ItemGroup>\n    <Content Include=\"@(SdkFile64)\" Exclude=\"$(WindowsSDKBuildToolsBinVersionedFolder)\\x64\\wintrust.dll.ini\">\n      <Pack>true</Pack>\n      <PackagePath>tools\\$(TargetFramework)\\any\\tools\\SDK\\x64</PackagePath>\n      <Visible>false</Visible>\n    </Content>\n    <Content Include=\"$(OutputPath)\\tools\\SDK\\x64\\wintrust.dll.ini\">\n      <Pack>true</Pack>\n      <PackagePath>tools\\$(TargetFramework)\\any\\tools\\SDK\\x64</PackagePath>\n      <Visible>false</Visible>\n    </Content>\n    <Content Include=\"@(SdkFile86)\">\n      <Pack>true</Pack>\n      <PackagePath>tools\\$(TargetFramework)\\any\\tools\\SDK\\x86</PackagePath>\n      <Visible>false</Visible>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "THIRD-PARTY-NOTICES.txt",
    "content": ".NET Core uses third-party libraries or other resources that may be\ndistributed under licenses different than the .NET Core software.\n\nAttributions and license notices for test cases originally authored by\nthird parties can be found in the respective test directories.\n\nIn the event that we accidentally failed to list a required notice, please\nbring it to our attention. Post an issue or email us:\n\n           dotnet@microsoft.com\n\nThe attached notices are provided for information only.\n\nLicense notice for .NET Reference Source\n-------------------------------\n\n﻿The MIT License (MIT)\n\nCopyright (c) Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy \nof this software and associated documentation files (the \"Software\"), to deal \nin the Software without restriction, including without limitation the rights \nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is \nfurnished to do so, subject to the following conditions: \n\nThe above copyright notice and this permission notice shall be included in all \ncopies or substantial portions of the Software. \n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \nSOFTWARE.\n\nAvailable at https://github.com/microsoft/referencesource/blob/master/LICENSE.txt\n\n\nLicense notice for Azure SDK for .NET\n-------------------------------\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nAvailable at https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt\n\n\nLicense notice for FiddlerCert\n-------------------------------\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Kevin Jones\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nAvailable at https://github.com/vcsjones/FiddlerCert/blob/main/license.txt\n\n\nLicense notice for Wyam\n-------------------------------\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Dave Glick\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nAvailable at https://github.com/Wyamio/Wyam/blob/develop/LICENSE\n\n\nLicense notice for OpenOpcSignTool\n-------------------------------\n\nMIT License\n\nCopyright (c) 2017 Kevin Jones\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nAvailable at https://github.com/vcsjones/OpenOpcSignTool/blob/main/LICENSE\n\n\nLicense notice for NuGetKeyVaultSignTool\n-------------------------------\n\nThe MIT License (MIT)\n\nCopyright (c) Claire Novotny\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\nAvailable at https://github.com/novotnyllc/NuGetKeyVaultSignTool/blob/main/LICENSE\n"
  },
  {
    "path": "docs/artifact-signing-integration.md",
    "content": "# Artifact Signing integration for Sign CLI\n\nThis document explains how to use the Sign CLI with a Artifact Signing account to perform code signing using the Artifact Signing provider. See `docs/signing-tool-spec.md` for higher-level background of this tool and the implementation at `src/Sign.SignatureProviders.TrustedSigning` for details.\n\n## Overview\n\nThe Sign CLI includes a `artifact-signing` provider that invokes the Artifact Signing service to obtain certificates and perform remote sign operations. The CLI uses the Azure SDK (`Azure.Identity`) for authentication.\n\nKey concepts for this provider:\n- Endpoint: the service URL for the Artifact Signing account.\n- Account name: the account within the Artifact Signing service.\n- Certificate profile: the certificate profile configured in the account that will be used to sign.\n\nFor more information, see the Artifact Signing [setup documentation](https://learn.microsoft.com/azure/artifact-signing/quickstart).\n\n## Prerequisites\n\n- An Azure subscription and a Artifact Signing account with at least one active certificate profile.\n- An identity (user, service principal, or managed identity) that has the `Artifact Signing Certificate Profile Signer` permission to perform signing.\n\n## How the CLI authenticates\n\nSign CLI uses Azure.Identity's credential chain by default (DefaultAzureCredential). This means the CLI will try an authentication flow automatically (Azure CLI login, environment variables for a service principal, managed identity, etc.). You may also explicitly choose a credential type with `--azure-credential-type`.\n\n## CLI options for Artifact Signing\n\nThe Artifact Signing subcommand is `sign code artifact-signing` and it requires the following options (short forms shown):\n\n- `--artifact-signing-endpoint`, `-ase` : the Artifact Signing service endpoint (URL).\n- `--artifact-signing-account`, `-asa` : the account name in the Artifact Signing service.\n- `--artifact-signing-certificate-profile`, `-ascp` : the certificate profile name to use for signing.\n\nThe Azure authentication options are available on the same command and include `--azure-credential-type` (`-act`) and managed identity options such as `--managed-identity-client-id` (`-mici`). By default, the CLI uses DefaultAzureCredential.\n\n## Examples\n\nReplace placeholders with your values.\n\nExample — sign a file using your current Azure CLI login (DefaultAzureCredential):\n\n```powershell\n# Ensure you're signed into Azure CLI\naz login\n\n# Sign a file using Artifact Signing\nsign code artifact-signing `\n  -ase https://<your-artifact-signing-endpoint> `\n  -asa <your-account-name> `\n  -ascp <your-certificate-profile> `\n  C:\\path\\to\\artifact.dll\n```\n\nExample — service principal (PowerShell session variables; prefer secrets or pipeline variables in CI):\n\n```powershell\n$env:AZURE_CLIENT_ID = 'your-client-id'\n$env:AZURE_TENANT_ID = 'your-tenant-id'\n\nsign code artifact-signing `\n  -ase https://<your-artifact-signing-endpoint> `\n  -asa <your-account-name> `\n  -ascp <your-certificate-profile> `\n  C:\\path\\to\\artifact.dll\n```\n\nExample — managed identity (useful for Azure-hosted agents):\n\n```powershell\n# Use managed identity by selecting the credential type explicitly and, if needed, the client id\nsign code artifact-signing `\n  -ase https://<your-artifact-signing-endpoint> `\n  -asa <your-account-name> `\n  -ascp <your-certificate-profile> `\n  -act managed-identity `\n  -mici <managed-identity-client-id> `\n  C:\\path\\to\\artifact.dll\n```\n\nNotes:\n- If you omit `-act`, the CLI uses DefaultAzureCredential, which already supports Azure CLI, environment variables for service principals, managed identities, and workload identity flows.\n- The endpoint URL and exact account/profile names are provided by your Artifact Signing onboarding or Azure portal.\n\n## CI/CD integration tips\n\n- Prefer federated identity (OIDC) or managed identities for CI agents to avoid long-lived secrets. Sign CLI supports workload and managed identity credential flows.\n- Store any required values (endpoint, account, certificate profile) as pipeline secrets or protected variables.\n\n## Troubleshooting\n\n- Authentication errors: verify the authentication method (Azure CLI login, environment variables, or managed identity) and that the identity has permission to the Artifact Signing account.\n- Permission errors: ensure your principal has the necessary rights on the Artifact Signing account and certificate profile. If unsure, contact your Azure admin or the team that provisioned the Artifact Signing account.\n- Endpoint/profile not found: confirm the exact endpoint URL, account name, and certificate profile name from your Artifact Signing account metadata or onboarding docs.\n- See the [Artifact Signing FAQ](https://learn.microsoft.com/azure/artifact-signing/faq) for more information.\n\n## Where to look in this repository\n\n- Implementation of the provider: `src/Sign.SignatureProviders.ArtifactSigning` (see `ArtifactSigningService.cs`, `RSAArtifactSigning.cs` and `ArtifactSigningServiceProvider.cs`).\n- CLI wiring: `src/Sign.Cli/ArtifactSigningCommand.cs` (shows required flags and how Azure credentials are constructed).\n"
  },
  {
    "path": "docs/azdo-build-and-sign.yml",
    "content": "trigger:\n- main\n- rel/*\n\npr:\n- main\n- rel/*\n\nstages:\n- stage: Build\n  jobs:\n  - job: Build\n    pool:\n      vmImage: ubuntu-latest\n    variables:\n      BuildConfiguration: Release\n\n    steps:\n\n    # Build steps  \n    - task: UseDotNet@2\n      displayName: 'Use .NET SDK 6.x'\n      inputs:\n        version: 6.x\n    - task: DotNetCoreCLI@2\n      inputs:\n        command: pack\n        packagesToPack: src/AClassLibrary/AClassLibrary.csproj\n        configuration: $(BuildConfiguration)\n        packDirectory: $(Build.ArtifactStagingDirectory)/Packages    \n        verbosityPack: Minimal\n      displayName: Build Package\n\n    # Publish the artifacts to sign and the file list, if any, as artifacts for the signing stage\n    - publish: $(Build.ArtifactStagingDirectory)/Packages   \n      displayName: Publish Build Artifacts  \n      artifact: BuildPackages\n\n    - publish: config\n      displayName: Publish signing file list\n      artifact: config\n\n- stage: CodeSign\n  dependsOn: Build\n  condition: and(succeeded('Build'), not(eq(variables['build.reason'], 'PullRequest'))) # Only run this stage on pushes to the main branch\n  jobs:\n  - job: CodeSign\n    displayName: Code Signing\n    pool:\n      vmImage: windows-latest # Code signing must run on a Windows agent for Authenticode signing (dll/exe)\n    variables:\n    - group: Sign Client Credentials # This is a variable group with secrets in it \n\n    steps:\n\n    # Retreive unsigned artifacts and file list\n    - download: current\n      artifact: config\n      displayName: Download signing file list\n\n    - download: current\n      artifact: BuildPackages\n      displayName: Download build artifacts\n\n    - task: UseDotNet@2\n      displayName: 'Use .NET SDK 6.x'\n      inputs:\n        version: 6.x\n\n    # Install the code signing tool\n    - task: DotNetCoreCLI@2\n      inputs:\n        command: custom\n        custom: tool\n        arguments: install --tool-path . sign --version 0.9.0-beta.23127.3\n      displayName: Install SignTool tool\n\n    # Run the signing command\n    - pwsh: |\n        .\\sign code azure-key-vault `\n        \"**/*.nupkg\" `\n        --base-directory \"$(Pipeline.Workspace)\\BuildPackages\" `\n        --file-list \"$(Pipeline.Workspace)\\config\\filelist.txt\" `\n        --publisher-name \"Contoso\" `\n        --description \"One Sign CLI demo\" `\n        --description-url \"https://github.com/dotnet/sign\" `\n        --azure-key-vault-tenant-id \"$(SignTenantId)\" `\n        --azure-key-vault-client-id \"$(SignClientId)\" `\n        --azure-key-vault-client-secret '$(SignClientSecret)' `\n        --azure-key-vault-certificate \"$(SignKeyVaultCertificate)\" `\n        --azure-key-vault-url \"$(SignKeyVaultUrl)\"\n      displayName: Sign packages\n    \n    # Publish the signed packages\n    - publish: $(Pipeline.Workspace)/BuildPackages\n      displayName: Publish Signed Packages\n      artifact: SignedPackages\n"
  },
  {
    "path": "docs/comparisons.md",
    "content": "# Signing Comparisons\n\n## NuGet\n\nThe following tables summarize differences between NuGet, dotnet, and Sign CLI's. \n\n### Features\n\nFeature | NuGet CLI | dotnet CLI | Sign CLI\n-- | -- | -- | --\nUse signing certificate from the file system | ✔️ | ✔️ | ❌\nUse signing certificate from a local store | ✔️ | ✔️ | ❌\nUse signing certificate from Azure Key Vault | ❌ | ❌ | ✔️\nIdentify signing certificate by fingerprint | ✔️ | ✔️ | ❌\nIdentify signing certificate by subject name | ✔️ | ✔️ | ❌\nIdentify signing certificate by name (user-defined) | ❌ | ❌ | ✔️\nCan skip timestamping | ✔️ | ✔️ | ❌\nOpt-in required to overwrite already signed package | ✔️ | ✔️ | ❌\nCan sign files (e.g.: *.dll) inside package | ❌ | ❌ | ✔️\nCan verify signed package | ✔️ | ✔️ | ❌\n\n### Platform support\n\nPlatform | NuGet CLI | dotnet CLI | Sign CLI\n-- | -- | -- | --\nWindows x86 | ✔️ | ✔️ | ❌\nWindows x64 | ✔️ | ✔️ | ✔️\nWindows ARM64 | ❌ | ✔️ | ❌\nLinux | ❌ | ✔️* | ❌\nmacOS | ❌ | ✔️* | ❌\n\n\\* NuGet signs packages not files within a package (e.g.:  DLL's).  On every platform where signing is supported, it is possible to sign a package that contains signable files which are unsigned.  Because Authenticode signing is only available on Windows, signing a NuGet package on Linux or macOS can more easily result in a signed package with unsigned files inside.  See https://github.com/NuGet/Home/issues/12362.\n\n### Requirements\n\nRequirement | NuGet CLI | dotnet CLI | Sign CLI\n-- | -- | -- | --\n.NET Framework | ✔️ (>= 4.7.2) | ❌ | ❌\n.NET SDK | ❌ | ✔️ (>= 5 on Windows, >= 7 on Linux, N/A on macOS) | ❌\n.NET Runtime | ❌ | ❌ | ✔️ (>= 6)\n\n## References\n* [sign command (NuGet CLI)](https://learn.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-sign)\n* [dotnet nuget sign](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-sign)"
  },
  {
    "path": "docs/file-globbing.md",
    "content": "# File List Filtering and Globbing\n\nThe `code` signing command supports the `--file-list` or `-fl` option. This option specifies a file that contains paths of files to sign or to exclude from signing.\n\nWhen using the file list option you must use a path relative to the working directory (or base directory, if used). You can change the base directory using `--base-directory` or `-b`.\n\nExample:\n\n`sign.exe code certificate-store -cf test.pfx -fl F:\\Sign\\file_sign_list.txt *`\n\n\n## File List Format\n\nYou can provide a list of string patterns (one pattern per line) which describe files to include or exclude, or literal file paths. Filtering uses globbing, and supports advanced features such as brace expansion and negation.\n\nThe following is supported:\n\n* Standard globbing: `*`, `?`, `**` wildcards.\n* Brace expansion: `{a,b}` expands to both `a` and `b`.\n  - Nested braces also work: `a{b,c{d,e}f}g` expands to `abg` `acdfg` `acefg`\n* Numeric ranges: `{1..3}` expands to `1`, `2`, `3`.\n* Negation: Patterns starting with `!` exclude files matching that pattern.\n* Escaping: Use `\\{`, `\\}`, or `\\!` to treat these characters literally.\n\n\n## Pattern Examples\n\n| Pattern                | Description                              | Matches Example(s)           |\n|------------------------|------------------------------------------|------------------------------|\n|`File.appx`             | Include `File.appx`                      | `File.appx`                  |\n|`!Installer.msix`       | Exclude `Installer.msix`                 | excludes `Installer.msix`    |\n|`*.txt`                 | All `.txt` files in the current directory  | `file.txt`, `notes.txt`      |\n|`**/*.cs`               | All `.cs` files in all subdirectories      | `src/Program.cs`             |\n|`docs/{README,HELP}.md` | `docs/README.md` and `docs/HELP.md`      | `docs/README.md`, `docs/HELP.md` |\n|`images/*.{png,jpg}`    | All `.png` and `.jpg` files in images      | `images/a.png`, `images/b.jpg`   |\n|`file{1..3}.log`        | `file1.log`, `file2.log`, `file3.log`    | `file2.log`                  |\n|`!bin/**`               | Exclude everything under `bin` directory   | excludes `bin/Debug/app.exe` |\n|`foo/\\{bar\\}.txt`       | Matches the literal file `foo/{bar}.txt`   | `foo/{bar}.txt`              |\n|`!**/obj/**`            | Exclude all files in any `obj` directory   | excludes `foo/obj/out.log`   |\n"
  },
  {
    "path": "docs/gh-build-and-sign.yml",
    "content": "name: Build and Sign\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\njobs:\n  build:    \n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n    \n    # Build steps  \n    - name: Setup .NET\n      uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: 6.x\n        \n    - name: Build Package\n      run: dotnet pack --configuration Release src/AClassLibrary/AClassLibrary.csproj\n    \n    # Publish the artifacts to sign and the file list, if any, as artifacts for the signing stage\n    - name: Upload signing file list\n      uses: actions/upload-artifact@v3\n      with:\n        name: config\n        path: config\n        \n    - name: Upload build artifacts\n      uses: actions/upload-artifact@v3\n      with:\n        name: BuildArtifacts\n        path: src/AClassLibrary/bin/Release/**/*.nupkg\n    \n  sign:\n    needs: build\n    runs-on: windows-latest # Code signing must run on a Windows agent for Authenticode signing (dll/exe)\n    if: ${{ github.ref == 'refs/heads/main' }} # Only run this job on pushes to the main branch\n    permissions:\n      id-token: write # Required for requesting the JWT\n      \n    steps:\n\n    # Download signing configuration and artifacts\n    - name: Download signing config\n      uses: actions/download-artifact@v3\n      with:\n        name: config\n        path: config\n        \n    - name: Download build artifacts\n      uses: actions/download-artifact@v3\n      with:\n        name: BuildArtifacts\n        path: BuildArtifacts\n    \n    # .NET is required on the agent for the tool to run\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: '9.x'\n\n    # Install the code signing tool    \n    - name: Install Sign CLI tool\n      run: dotnet tool install --tool-path . --prerelease sign\n    \n    # Login to Azure using a ServicePrincipal configured to authenticate agaist a GitHub Action\n    - name: 'Az CLI login'\n      uses: azure/login@v1\n      with:\n        allow-no-subscriptions: true\n        client-id: ${{ secrets.AZURE_CLIENT_ID }} # This does not need to be a secret and is just a placeholder\n        tenant-id: ${{ secrets.AZURE_TENANT_ID }} # This does not need to be a secret and is just a placeholder\n\n    # Run the signing command\n    - name: Sign artifacts\n      shell: pwsh\n      run: >\n        ./sign code azure-key-vault\n        **/*.nupkg\n        --base-directory \"${{ github.workspace }}/BuildArtifacts\"\n        --file-list \"${{ github.workspace }}/config/filelist.txt\"\n        --publisher-name \"Contoso\"\n        --description \"One Sign CLI demo\"\n        --description-url \"https://github.com/dotnet/sign\"\n        --azure-credential-type \"azure-cli\"\n        --azure-key-vault-url \"${{ secrets.KEY_VAULT_URL }}\" # This does not need to be a secret and is just a placeholder\n        --azure-key-vault-certificate \"${{ secrets.KEY_VAULT_CERTIFICATE_ID }}\" # This does not need to be a secret and is just a placeholder\n    \n    # Publish the signed packages\n    - name: Upload build artifacts\n      uses: actions/upload-artifact@v3\n      with:\n        name: SignedArtifacts\n        path: BuildArtifacts\n"
  },
  {
    "path": "docs/signing-tool-spec.md",
    "content": "# Signing CLI tool\n\n## Background\n\nCode signing is a way to provide tamper detection to binary files and provide a way of establishing identity. There are different code signing mechanisms, but the most common on Windows and .NET are based on X.509 certificates.\n\nThere are several technology areas within the Windows and .NET ecosystem that support code signing:\n\n- PE files & certain scripts via Authenticode (dll, exe, ps1, sys)\n- MSIX via Authenticode (msix, msixbundle) & related manifests\n- Visual Studio Extensions (VSIX) via Open Packaging Convention\n- ClickOnce & VSTO via Mage (XML Digital Signatures)\n- NuGet Packages\n\nToday each of these areas has their own tools (SignTool, VISXSignTool, Mage, NuGet) to create signatures. Each tool has its own set of parameters and are written to assume use of the local certificate store API's by default. Without a shared implementation, a new code signing requirement can require individual updates to each tool. In May 2022, the CA/Browser Forum updated its [baseline requirements for publicly trusted code signing certificates](https://cabforum.org/wp-content/uploads/Baseline-Requirements-for-the-Issuance-and-Management-of-Code-Signing.v3.2.pdf) to require that all new code signing certificates issued after June 2023 use hardware security modules (HSM's) to prevent private key theft. While some HSM's contain CSP/KSP support to expose certificates through Windows' certificate store API's, they frequently contain significant limitations, such as requiring an interactive session to authenticate to the device. This makes signing code in the cloud and on build agents extremely difficult for mainline scenarios.\n\nThere are many HSM cloud services, including Azure Key Vault, that meet the updated key storage requirements, however we do not have first-party support for signing code with those services. There are open source community solutions to fill this gap, such as:\n\n* [AzureSignTool](https://github.com/vcsjones/AzureSignTool)\n* [NuGetKeyVaultSignTool](https://github.com/novotnyllc/NuGetKeyVaultSignTool)\n* [OpenOpcSignTool](https://github.com/vcsjones/OpenOpcSignTool)\n\nThe [.NET Foundation Signing Service](https://github.com/dotnet/sign/tree/legacy-service/servicing) builds on these solutions, adds additional supported file formats, and orchestrates signing the various file types in the right order.\n\nWhile existing community solutions help, they leave the complicated work of signing the files in the right order to each user and support only Azure Key Vault. With the [announcement](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/azure-code-signing-democratizing-trust-for-developers-and/ba-p/3604669) of Azure Code Signing and the move towards HSM's, there's a need to support multiple code signing providers in our signing tools.\n\n## Challenges\n\nThere are a few challenges around code signing:\n\n### Local Certificates\n\nToday the code signing tooling in the Windows and .NET SDK uses PFX (public/private certificate key pair files or the local certificate store for obtaining certificates). There risks to this approach:\n\n- PFX files are targets in data breaches; their passwords can be cracked\n- Certificates in a local store can be used by any app/malware\n- There’s no revocation mechanism for a user's access to the certificate; they always have it\n- No auditing of signing operations possible\n- EV code signing certificates aren’t easily supported as they require FIPS 140-2 hardware devices with drivers\n\nIn May 2022, the CA/Browser Forum updated its baseline requirements to require HSM's so local certificates will no longer be issued for publicly trusted code signing certificates. The only support the current signing tools have for this scenario is via CSP/KSP drivers provided by some HSM vendors, and those do not work well for cloud-based build agents. The current tools would need new investment to support different backends.\n\n### Orchestration\n\nAn application/library package typically contains multiple assets that need to be signed. For example, a NuGet package (`.nupkg` file) contains `.dll` files that also must be signed. A ClickOnce or MSIX package also contains `.dll` or `.exe` files that need to be signed. A `.vsix` file can contain `.dll` files and `.nupkg` file that must be signed. These files need to be signed \"inside out\" to ensure the proper sequence. That is, a `.vsix` containing a `.nupkg` needs to extract the inner `.nupkg` to sign the contained `.dll` files, then sign the `.nupkg` and any other `.dll` files, then repack and sign the `.vsix`. Other types, like ClickOnce and MSIX may contain manifest files that also must be updated during these operations.\n\nTo properly sign all assets, multiple signing tools must be used, and each tool has its own command line syntax, options, and default. The process of code signing is error-prone and hard to get right. The signing tool addresses these challenges by unifying the interface into a single set of options.\n\n## Proposal\n\nCreate a modern signing tool to eventually replace the existing tools. The tool will handle all of our first party signing formats, orchestrate signing files in the right order, and have extensibility to support multiple raw signature providers. As our customers use a variety of clouds and HSM's, the extensibility will enable us to meet our customers' needs wherever they store their certificates.\n\nWhile some of this could be done via an MSBuild task, a CLI tool is preferable to MSBuild tasks for a couple reasons:\n\n- **Performance:** During a build, many binary artifacts are created that need to be signed. A multi-targeted NuGet package may contain several `.dll` files. An application will likely contain more than one file that needs to be signed. It's much more efficient to pass them all to a signing tool where parallelism is possible than to sign during the inner-loop.\n- **Security:** Code signing is a sensitive operation that requires credentials/secrets. Use of these secrets should be as limited as possible to prevent leakage into the rest of a build pipeline, such as log files or unrelated build tasks. Ideally, a CI pipeline should contain a separate stage for code signing to ensure that credentials are never unintentionally exposed to a build stage.\n- **Platform:** Authenticode is currently limited to Windows. Thus, while it's possible to sign a NuGet or VSIX cross-platform, the DLL's inside can't be signed unless running on Windows. With the NuGet packages being developer-only artifacts--they're not shipped with the apps--it's critical that the DLL's inside are also signed. Builds for binaries may run on any platform, but as signing is a discreet step in most CI pipelines, it's reasonable to require a Windows build agent for this task.\n\n### Roadmap\n\nThe scope of the preview release will be limited to the existing funtionality currently in the service. The remaining functionality in this spec will be delivered in a later 1.0 release. The .NET Foundation has a dependency on this tool being delivered by [June 30, 2023](https://learn.microsoft.com/en-us/answers/questions/768833/when-is-adal-and-azure-ad-graph-reaching-end-of-li.html).\n\n#### Preview\n\n**Goals**\n\n- Support for Authenticode, VSIX, NuGet (author signature), ClickOnce\n- Only run on Windows x64.\n- Support a single certificate for all files in the operation.\n\n**Non-Goals**\n\n- Strong Name signing won't be in v1; guidance is to use an snk not based on a cert. If easy, perhaps can revisit.\n- Containers, including Notary v2 support.\n- Extensibility. v1 will support different signing providers.\n- Support Authenticode on platforms other than Windows x64. Future work will be required to support ARM64 and non-Windows hosts. Support for certain file types may be limited due to platform support.\n- Offline distribution.\n\n#### v1\n\n**Goals**\n\n- Extensibility mechanism to support different code signing providers with a dynamic lookup so the core client remains agnostic of the backend\n- Offline distribution for core plus backend provider\n- Three providers: Certificate Store, Azure Key Vault, Azure Code Signing\n- Support for additional formats: [.HLKX](https://github.com/dotnet/sign/issues/422), [VBA](https://github.com/dotnet/sign/issues/364)\n- Verification of signatures\n\n\n"
  },
  {
    "path": "eng/PoliCheckExclusions.xml",
    "content": "﻿<!-- Original source:  https://github.com/dotnet/install-scripts/blob/707d374fc90068daedb5048ce95a1b34d269995e/eng/policheck_exclusions.xml -->\n<PoliCheckExclusions>\n  <!-- All strings must be UPPER CASE -->\n  <!--Each of these exclusions is a folder name -if \\[name]\\exists in the file path, it will be skipped -->\n  <!--<Exclusion Type=\"FolderPathFull\">ABC|XYZ</Exclusion>-->\n  <!--Each of these exclusions is a folder name -if any folder or file starts with \"\\[name]\", it will be skipped -->\n  <!--<Exclusion Type=\"FolderPathStart\">ABC|XYZ</Exclusion>-->\n  <!--Each of these file types will be completely skipped for the entire scan -->\n  <!--<Exclusion Type=\"FileType\">.ABC|.XYZ</Exclusion>-->\n  <!--The specified file names will be skipped during the scan regardless which folder they are in -->\n  <!--<Exclusion Type=\"FileName\">ABC.TXT|XYZ.CS</Exclusion>-->\n  <Exclusion Type=\"FolderPathFull\">.DOTNET</Exclusion>\n</PoliCheckExclusions>"
  },
  {
    "path": "eng/Signing.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n   <PropertyGroup>\n    <UseDotNetCertificate>true</UseDotNetCertificate>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ItemsToSign Remove=\"@(ItemsToSign)\" />\n    <ItemsToSign Include=\"$(ArtifactsShippingPackagesDir)/*.nupkg\" />\n  </ItemGroup>\n\n  <!--\n    These 3rd-party libraries are already 3rd party signed; however, we must add a second signature with this certificate.\n  -->\n  <ItemGroup>\n    <FileSignInfo Include=\"AzureSign.Core.dll\" CertificateName=\"3PartySHA2\" />\n    <FileSignInfo Include=\"Newtonsoft.Json.dll\" CertificateName=\"3PartySHA2\" />\n    <FileSignInfo Include=\"NuGetKeyVaultSignTool.Core.dll\" CertificateName=\"3PartySHA2\" />\n    <FileSignInfo Include=\"RSAKeyVaultProvider.dll\" CertificateName=\"3PartySHA2\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "eng/Version.Details.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Dependencies>\n  <Source Uri=\"https://github.com/dotnet/dotnet\" Mapping=\"arcade\" Sha=\"8b29a1682219da555ee27e4fdda55dc3884b316f\" BarId=\"277635\" />\n  <ProductDependencies>\n  </ProductDependencies>\n  <ToolsetDependencies>\n    <Dependency Name=\"Microsoft.DotNet.Arcade.Sdk\" Version=\"10.0.0-beta.26222.2\">\n      <Uri>https://github.com/dotnet/arcade</Uri>\n      <Sha>58713cb9a664ed67642127fcaf70b8c0c3b55ef2</Sha>\n    </Dependency>\n  </ToolsetDependencies>\n</Dependencies>\n"
  },
  {
    "path": "eng/Versions.props",
    "content": "<Project>\n  <Import Project=\"Version.Details.props\" Condition=\"Exists('Version.Details.props')\" />\n  <PropertyGroup>\n    <!-- This repo version -->\n    <VersionPrefix>0.9.1</VersionPrefix>\n    <PreReleaseVersionLabel>beta</PreReleaseVersionLabel>\n    <!-- Don't allow netstandard1.x dependencies in this repository. -->\n    <FlagNetStandard1XDependencies>true</FlagNetStandard1XDependencies>\n  </PropertyGroup>\n  <!-- maintenance-packages -->\n  <PropertyGroup Condition=\"'$(DotNetBuildSourceOnly)' == 'true'\">\n    <MicrosoftBclHashCodeVersion>6.0.0</MicrosoftBclHashCodeVersion>\n    <SystemMemoryVersion>4.6.3</SystemMemoryVersion>\n    <MicrosoftIORedistVersion>6.1.3</MicrosoftIORedistVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DotNetBuildSourceOnly)' != 'true'\">\n    <MicrosoftBclHashCodeVersion>1.1.1</MicrosoftBclHashCodeVersion>\n    <SystemMemoryVersion>4.5.5</SystemMemoryVersion>\n    <MicrosoftIORedistVersion>6.0.1</MicrosoftIORedistVersion>\n  </PropertyGroup>\n  <PropertyGroup>\n    <!-- arcade -->\n    <MicrosoftDotNetSwaggerGeneratorMSBuildVersion>9.0.0-beta.24223.1</MicrosoftDotNetSwaggerGeneratorMSBuildVersion>\n    <!-- corefx -->\n    <SystemRuntimeInteropServicesRuntimeInformation>4.3.0</SystemRuntimeInteropServicesRuntimeInformation>\n    <!-- netstandard -->\n    <NETStandardLibraryVersion>2.0.3</NETStandardLibraryVersion>\n    <!-- nuget -->\n    <!-- Important: Don't version higher than what's available in the toolset SDK as\n         NuGet assemblies aren't redistributed with .NETCoreApp msbuild tasks. -->\n    <NuGetCommandsVersion>6.13.2</NuGetCommandsVersion>\n    <NuGetFrameworksVersion>6.13.2</NuGetFrameworksVersion>\n    <NuGetPackagingVersion>6.13.2</NuGetPackagingVersion>\n    <NuGetProjectModelVersion>6.13.2</NuGetProjectModelVersion>\n    <NuGetVersioningVersion>6.13.2</NuGetVersioningVersion>\n    <!-- runtime -->\n    <MicrosoftNETCorePlatformsVersion>5.0.0</MicrosoftNETCorePlatformsVersion>\n    <MicrosoftNETRuntimeEmscripten2023Nodewin_x64>6.0.4</MicrosoftNETRuntimeEmscripten2023Nodewin_x64>\n    <MicrosoftNETRuntimeEmscripten2023Pythonwin_x64>6.0.4</MicrosoftNETRuntimeEmscripten2023Pythonwin_x64>\n    <MicrosoftNETRuntimeEmscripten2023Sdkwin_x64>6.0.4</MicrosoftNETRuntimeEmscripten2023Sdkwin_x64>\n    <MicrosoftNETWorkloadBaselineVersion>9.0.100-baseline.1.23464.1</MicrosoftNETWorkloadBaselineVersion>\n    <MicrosoftNETWorkloadEmscriptenManifest_60200Version>6.0.4</MicrosoftNETWorkloadEmscriptenManifest_60200Version>\n    <MicrosoftNETWorkloadEmscriptenManifest_80100Preview6Version>8.0.0-preview.6.23326.2</MicrosoftNETWorkloadEmscriptenManifest_80100Preview6Version>\n    <MicrosoftNETWorkloadMonoToolChainManifest_60200Version>6.0.3</MicrosoftNETWorkloadMonoToolChainManifest_60200Version>\n    <MicrosoftNETWorkloadMonoToolChainManifest_60200Version_604>6.0.4</MicrosoftNETWorkloadMonoToolChainManifest_60200Version_604>\n    <MicrosoftNETWorkloadMonoToolChainManifest_60300Version_6021>6.0.21</MicrosoftNETWorkloadMonoToolChainManifest_60300Version_6021>\n    <MicrosoftNETWorkloadMonoToolChainManifest_60300Version_6022>6.0.22</MicrosoftNETWorkloadMonoToolChainManifest_60300Version_6022>\n    <MicrosoftiOSTemplatesVersion>15.2.302-preview.14.122</MicrosoftiOSTemplatesVersion>\n    <MicrosoftiOSTemplatesVersion160527>16.0.527</MicrosoftiOSTemplatesVersion160527>\n    <SystemCompositionVersion>9.0.0-preview.6.24327.7</SystemCompositionVersion>\n    <!-- vstest -->\n    <MicrosoftNetTestSdkVersion>17.5.0</MicrosoftNetTestSdkVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "eng/common/BuildConfiguration/build-configuration.json",
    "content": "{\n  \"RetryCountLimit\": 1,\n  \"RetryByAnyError\": false\n}\n"
  },
  {
    "path": "eng/common/CIBuild.cmd",
    "content": "@echo off\npowershell -ExecutionPolicy ByPass -NoProfile -command \"& \"\"\"%~dp0Build.ps1\"\"\" -restore -build -test -sign -pack -publish -ci %*\"\n"
  },
  {
    "path": "eng/common/PSScriptAnalyzerSettings.psd1",
    "content": "@{\n    IncludeRules=@('PSAvoidUsingCmdletAliases',\n                   'PSAvoidUsingWMICmdlet',\n                   'PSAvoidUsingPositionalParameters',\n                   'PSAvoidUsingInvokeExpression',\n                   'PSUseDeclaredVarsMoreThanAssignments',\n                   'PSUseCmdletCorrectly',\n                   'PSStandardDSCFunctionsInResource',\n                   'PSUseIdenticalMandatoryParametersForDSC',\n                   'PSUseIdenticalParametersForDSC')\n}"
  },
  {
    "path": "eng/common/README.md",
    "content": "# Don't touch this folder\n\n                uuuuuuuuuuuuuuuuuuuu\n              u\" uuuuuuuuuuuuuuuuuu \"u\n            u\" u$$$$$$$$$$$$$$$$$$$$u \"u\n          u\" u$$$$$$$$$$$$$$$$$$$$$$$$u \"u\n        u\" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$u \"u\n      u\" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u \"u\n    u\" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u \"u\n    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $\n    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $\n    $ $$$\" ... \"$...  ...$\" ... \"$$$  ... \"$$$ $\n    $ $$$u `\"$$$$$$$  $$$  $$$$$  $$  $$$  $$$ $\n    $ $$$$$$uu \"$$$$  $$$  $$$$$  $$  \"\"\" u$$$ $\n    $ $$$\"\"$$$  $$$$  $$$u \"$$$\" u$$  $$$$$$$$ $\n    $ $$$$....,$$$$$..$$$$$....,$$$$..$$$$$$$$ $\n    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $\n    \"u \"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\" u\"\n      \"u \"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\" u\"\n        \"u \"$$$$$$$$$$$$$$$$$$$$$$$$$$$$\" u\"\n          \"u \"$$$$$$$$$$$$$$$$$$$$$$$$\" u\"\n            \"u \"$$$$$$$$$$$$$$$$$$$$\" u\"\n              \"u \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" u\"\n                \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n!!! Changes made in this directory are subject to being overwritten by automation !!!\n\nThe files in this directory are shared by all Arcade repos and managed by automation. If you need to make changes to these files, open an issue or submit a pull request to https://github.com/dotnet/arcade first.\n"
  },
  {
    "path": "eng/common/SetupNugetSources.ps1",
    "content": "# This script adds internal feeds required to build commits that depend on internal package sources. For instance,\n# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly,\n# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present.\n# In addition, this script also enables disabled internal Maestro (darc-int*) feeds.\n#\n# Optionally, this script also adds a credential entry for each of the internal feeds if supplied.\n#\n# See example call for this script below.\n#\n#  - task: PowerShell@2\n#    displayName: Setup internal Feeds Credentials\n#    condition: eq(variables['Agent.OS'], 'Windows_NT')\n#    inputs:\n#      filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1\n#      arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $Env:Token\n#    env:\n#      Token: $(dn-bot-dnceng-artifact-feeds-rw)\n#\n# Note that the NuGetAuthenticate task should be called after SetupNugetSources.\n# This ensures that:\n# - Appropriate creds are set for the added internal feeds (if not supplied to the scrupt)\n# - The credential provider is installed.\n#\n# This logic is also abstracted into enable-internal-sources.yml.\n\n[CmdletBinding()]\nparam (\n    [Parameter(Mandatory = $true)][string]$ConfigFile,\n    $Password\n)\n\n$ErrorActionPreference = \"Stop\"\nSet-StrictMode -Version 2.0\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\n. $PSScriptRoot\\tools.ps1\n\n# Adds or enables the package source with the given name\nfunction AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) {\n    if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName)) {\n        AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $userName -pwd $Password\n    }\n}\n\n# Add source entry to PackageSources\nfunction AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) {\n    $packageSource = $sources.SelectSingleNode(\"add[@key='$SourceName']\")\n    \n    if ($packageSource -eq $null)\n    {\n        Write-Host \"Adding package source $SourceName\"\n\n        $packageSource = $doc.CreateElement(\"add\")\n        $packageSource.SetAttribute(\"key\", $SourceName)\n        $packageSource.SetAttribute(\"value\", $SourceEndPoint)\n        $sources.AppendChild($packageSource) | Out-Null\n    }\n    else {\n        Write-Host \"Package source $SourceName already present and enabled.\"\n    }\n\n    AddCredential -Creds $creds -Source $SourceName -Username $Username -pwd $pwd\n}\n\n# Add a credential node for the specified source\nfunction AddCredential($creds, $source, $username, $pwd) {\n    # If no cred supplied, don't do anything.\n    if (!$pwd) {\n        return;\n    }\n\n    Write-Host \"Inserting credential for feed: \" $source\n\n    # Looks for credential configuration for the given SourceName. Create it if none is found.\n    $sourceElement = $creds.SelectSingleNode($Source)\n    if ($sourceElement -eq $null)\n    {\n        $sourceElement = $doc.CreateElement($Source)\n        $creds.AppendChild($sourceElement) | Out-Null\n    }\n\n    # Add the <Username> node to the credential if none is found.\n    $usernameElement = $sourceElement.SelectSingleNode(\"add[@key='Username']\")\n    if ($usernameElement -eq $null)\n    {\n        $usernameElement = $doc.CreateElement(\"add\")\n        $usernameElement.SetAttribute(\"key\", \"Username\")\n        $sourceElement.AppendChild($usernameElement) | Out-Null\n    }\n    $usernameElement.SetAttribute(\"value\", $Username)\n\n    # Add the <ClearTextPassword> to the credential if none is found.\n    # Add it as a clear text because there is no support for encrypted ones in non-windows .Net SDKs.\n    #   -> https://github.com/NuGet/Home/issues/5526\n    $passwordElement = $sourceElement.SelectSingleNode(\"add[@key='ClearTextPassword']\")\n    if ($passwordElement -eq $null)\n    {\n        $passwordElement = $doc.CreateElement(\"add\")\n        $passwordElement.SetAttribute(\"key\", \"ClearTextPassword\")\n        $sourceElement.AppendChild($passwordElement) | Out-Null\n    }\n    \n    $passwordElement.SetAttribute(\"value\", $pwd)\n}\n\n# Enable all darc-int package sources.\nfunction EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds) {\n    $maestroInternalSources = $DisabledPackageSources.SelectNodes(\"add[contains(@key,'darc-int')]\")\n    ForEach ($DisabledPackageSource in $maestroInternalSources) {\n        EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key\n    }\n}\n\n# Enables an internal package source by name, if found. Returns true if the package source was found and enabled, false otherwise.\nfunction EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName) {\n    $DisabledPackageSource = $DisabledPackageSources.SelectSingleNode(\"add[@key='$PackageSourceName']\")\n    if ($DisabledPackageSource) {\n        Write-Host \"Enabling internal source '$($DisabledPackageSource.key)'.\"\n        \n        # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries\n        $DisabledPackageSources.RemoveChild($DisabledPackageSource)\n\n        AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -pwd $Password\n        return $true\n    }\n    return $false\n}\n\nif (!(Test-Path $ConfigFile -PathType Leaf)) {\n  Write-PipelineTelemetryError -Category 'Build' -Message \"Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile\"\n  ExitWithExitCode 1\n}\n\n# Load NuGet.config\n$doc = New-Object System.Xml.XmlDocument\n$filename = (Get-Item $ConfigFile).FullName\n$doc.Load($filename)\n\n# Get reference to <PackageSources> - fail if none exist\n$sources = $doc.DocumentElement.SelectSingleNode(\"packageSources\")\nif ($sources -eq $null) {\n    Write-PipelineTelemetryError -Category 'Build' -Message \"Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. NuGet config file must contain a packageSources section: $ConfigFile\"\n    ExitWithExitCode 1\n}\n\n$creds = $null\n$feedSuffix = \"v3/index.json\"\nif ($Password) {\n    $feedSuffix = \"v2\"\n    # Looks for a <PackageSourceCredentials> node. Create it if none is found.\n    $creds = $doc.DocumentElement.SelectSingleNode(\"packageSourceCredentials\")\n    if ($creds -eq $null) {\n        $creds = $doc.CreateElement(\"packageSourceCredentials\")\n        $doc.DocumentElement.AppendChild($creds) | Out-Null\n    }\n}\n\n$userName = \"dn-bot\"\n\n# Check for disabledPackageSources; we'll enable any darc-int ones we find there\n$disabledSources = $doc.DocumentElement.SelectSingleNode(\"disabledPackageSources\")\nif ($disabledSources -ne $null) {\n    Write-Host \"Checking for any darc-int disabled package sources in the disabledPackageSources node\"\n    EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds\n}\n$dotnetVersions = @('5','6','7','8','9','10')\n\nforeach ($dotnetVersion in $dotnetVersions) {\n    $feedPrefix = \"dotnet\" + $dotnetVersion;\n    $dotnetSource = $sources.SelectSingleNode(\"add[@key='$feedPrefix']\")\n    if ($dotnetSource -ne $null) {\n        AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName \"$feedPrefix-internal\" -SourceEndPoint \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix\" -Creds $creds -Username $userName -pwd $Password\n        AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName \"$feedPrefix-internal-transport\" -SourceEndPoint \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix\" -Creds $creds -Username $userName -pwd $Password\n    }\n}\n\n# Check for dotnet-eng and add dotnet-eng-internal if present\n$dotnetEngSource = $sources.SelectSingleNode(\"add[@key='dotnet-eng']\")\nif ($dotnetEngSource -ne $null) {\n    AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName \"dotnet-eng-internal\" -SourceEndPoint \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$feedSuffix\" -Creds $creds -Username $userName -pwd $Password\n}\n\n# Check for dotnet-tools and add dotnet-tools-internal if present\n$dotnetToolsSource = $sources.SelectSingleNode(\"add[@key='dotnet-tools']\")\nif ($dotnetToolsSource -ne $null) {\n    AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName \"dotnet-tools-internal\" -SourceEndPoint \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$feedSuffix\" -Creds $creds -Username $userName -pwd $Password\n}\n\n$doc.Save($filename)\n"
  },
  {
    "path": "eng/common/SetupNugetSources.sh",
    "content": "#!/usr/bin/env bash\n\n# This script adds internal feeds required to build commits that depend on internal package sources. For instance,\n# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly,\n# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present.\n# In addition, this script also enables disabled internal Maestro (darc-int*) feeds.\n# \n# Optionally, this script also adds a credential entry for each of the internal feeds if supplied.\n#\n# See example call for this script below.\n#\n#  - task: Bash@3\n#    displayName: Setup Internal Feeds\n#    inputs:\n#      filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.sh\n#      arguments: $(System.DefaultWorkingDirectory)/NuGet.config\n#    condition: ne(variables['Agent.OS'], 'Windows_NT')\n#  - task: NuGetAuthenticate@1\n#\n# Note that the NuGetAuthenticate task should be called after SetupNugetSources.\n# This ensures that:\n# - Appropriate creds are set for the added internal feeds (if not supplied to the scrupt)\n# - The credential provider is installed.\n#\n# This logic is also abstracted into enable-internal-sources.yml.\n\nConfigFile=$1\nCredToken=$2\nNL='\\n'\nTB='    '\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. \"$scriptroot/tools.sh\"\n\nif [ ! -f \"$ConfigFile\" ]; then\n    Write-PipelineTelemetryError -Category 'Build' \"Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile\"\n    ExitWithExitCode 1\nfi\n\nif [[ `uname -s` == \"Darwin\" ]]; then\n    NL=$'\\\\\\n'\n    TB=''\nfi\n\n# Enables an internal package source by name, if found. Returns 0 if found and enabled, 1 if not found.\nEnableInternalPackageSource() {\n    local PackageSourceName=\"$1\"\n    \n    # Check if disabledPackageSources section exists\n    grep -i \"<disabledPackageSources>\" \"$ConfigFile\" > /dev/null\n    if [ \"$?\" != \"0\" ]; then\n        return 1  # No disabled sources section\n    fi\n    \n    # Check if this source name is disabled\n    grep -i \"<add key=\\\"$PackageSourceName\\\" value=\\\"true\\\"\" \"$ConfigFile\" > /dev/null\n    if [ \"$?\" == \"0\" ]; then\n        echo \"Enabling internal source '$PackageSourceName'.\"\n        # Remove the disabled entry (including any surrounding comments or whitespace on the same line)\n        sed -i.bak \"/<add key=\\\"$PackageSourceName\\\" value=\\\"true\\\" \\/>/d\" \"$ConfigFile\"\n        \n        # Add the source name to PackageSources for credential handling\n        PackageSources+=(\"$PackageSourceName\")\n        return 0  # Found and enabled\n    fi\n    \n    return 1  # Not found in disabled sources\n}\n\n# Add source entry to PackageSources\nAddPackageSource() {\n    local SourceName=\"$1\"\n    local SourceEndPoint=\"$2\"\n    \n    # Check if source already exists\n    grep -i \"<add key=\\\"$SourceName\\\"\" \"$ConfigFile\" > /dev/null\n    if [ \"$?\" == \"0\" ]; then\n        echo \"Package source $SourceName already present and enabled.\"\n        PackageSources+=(\"$SourceName\")\n        return\n    fi\n    \n    echo \"Adding package source $SourceName\"\n    PackageSourcesNodeFooter=\"</packageSources>\"\n    PackageSourceTemplate=\"${TB}<add key=\\\"$SourceName\\\" value=\\\"$SourceEndPoint\\\" />\"\n    \n    sed -i.bak \"s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|\" \"$ConfigFile\"\n    PackageSources+=(\"$SourceName\")\n}\n\n# Adds or enables the package source with the given name\nAddOrEnablePackageSource() {\n    local SourceName=\"$1\"\n    local SourceEndPoint=\"$2\"\n    \n    # Try to enable if disabled, if not found then add new source\n    EnableInternalPackageSource \"$SourceName\"\n    if [ \"$?\" != \"0\" ]; then\n        AddPackageSource \"$SourceName\" \"$SourceEndPoint\"\n    fi\n}\n\n# Enable all darc-int package sources\nEnableMaestroInternalPackageSources() {\n    # Check if disabledPackageSources section exists\n    grep -i \"<disabledPackageSources>\" \"$ConfigFile\" > /dev/null\n    if [ \"$?\" != \"0\" ]; then\n        return  # No disabled sources section\n    fi\n    \n    # Find all darc-int disabled sources\n    local DisabledDarcIntSources=()\n    DisabledDarcIntSources+=$(grep -oh '\"darc-int-[^\"]*\" value=\"true\"' \"$ConfigFile\" | tr -d '\"')\n    \n    for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do\n        if [[ $DisabledSourceName == darc-int* ]]; then\n            EnableInternalPackageSource \"$DisabledSourceName\"\n        fi\n    done\n}\n\n# Ensure there is a <packageSources>...</packageSources> section.\ngrep -i \"<packageSources>\" $ConfigFile\nif [ \"$?\" != \"0\" ]; then\n    Write-PipelineTelemetryError -Category 'Build' \"Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. NuGet config file must contain a packageSources section: $ConfigFile\"\n    ExitWithExitCode 1\nfi\n\nPackageSources=()\n\n# Set feed suffix based on whether credentials are provided\nFeedSuffix=\"v3/index.json\"\nif [ -n \"$CredToken\" ]; then\n    FeedSuffix=\"v2\"\n    \n    # Ensure there is a <packageSourceCredentials>...</packageSourceCredentials> section.\n    grep -i \"<packageSourceCredentials>\" $ConfigFile\n    if [ \"$?\" != \"0\" ]; then\n        echo \"Adding <packageSourceCredentials>...</packageSourceCredentials> section.\"\n\n        PackageSourcesNodeFooter=\"</packageSources>\"\n        PackageSourceCredentialsTemplate=\"${TB}<packageSourceCredentials>${NL}${TB}</packageSourceCredentials>\"\n\n        sed -i.bak \"s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|\" $ConfigFile\n    fi\nfi\n\n# Check for disabledPackageSources; we'll enable any darc-int ones we find there\ngrep -i \"<disabledPackageSources>\" $ConfigFile > /dev/null\nif [ \"$?\" == \"0\" ]; then\n    echo \"Checking for any darc-int disabled package sources in the disabledPackageSources node\"\n    EnableMaestroInternalPackageSources\nfi\n\nDotNetVersions=('5' '6' '7' '8' '9' '10')\n\nfor DotNetVersion in ${DotNetVersions[@]} ; do\n    FeedPrefix=\"dotnet${DotNetVersion}\";\n    grep -i \"<add key=\\\"$FeedPrefix\\\"\" $ConfigFile > /dev/null\n    if [ \"$?\" == \"0\" ]; then\n        AddOrEnablePackageSource \"$FeedPrefix-internal\" \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/$FeedPrefix-internal/nuget/$FeedSuffix\"\n        AddOrEnablePackageSource \"$FeedPrefix-internal-transport\" \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/$FeedPrefix-internal-transport/nuget/$FeedSuffix\"\n    fi\ndone\n\n# Check for dotnet-eng and add dotnet-eng-internal if present\ngrep -i \"<add key=\\\"dotnet-eng\\\"\" $ConfigFile > /dev/null\nif [ \"$?\" == \"0\" ]; then\n    AddOrEnablePackageSource \"dotnet-eng-internal\" \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$FeedSuffix\"\nfi\n\n# Check for dotnet-tools and add dotnet-tools-internal if present\ngrep -i \"<add key=\\\"dotnet-tools\\\"\" $ConfigFile > /dev/null\nif [ \"$?\" == \"0\" ]; then\n    AddOrEnablePackageSource \"dotnet-tools-internal\" \"https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$FeedSuffix\"\nfi\n\n# I want things split line by line\nPrevIFS=$IFS\nIFS=$'\\n'\nPackageSources+=\"$IFS\"\nPackageSources+=$(grep -oh '\"darc-int-[^\"]*\"' $ConfigFile | tr -d '\"')\nIFS=$PrevIFS\n\nif [ \"$CredToken\" ]; then\n    for FeedName in ${PackageSources[@]} ; do\n        # Check if there is no existing credential for this FeedName\n        grep -i \"<$FeedName>\" $ConfigFile \n        if [ \"$?\" != \"0\" ]; then\n            echo \"\tInserting credential for feed: $FeedName\"\n\n            PackageSourceCredentialsNodeFooter=\"</packageSourceCredentials>\"\n            NewCredential=\"${TB}${TB}<$FeedName>${NL}${TB}<add key=\\\"Username\\\" value=\\\"dn-bot\\\" />${NL}${TB}${TB}<add key=\\\"ClearTextPassword\\\" value=\\\"$CredToken\\\" />${NL}${TB}${TB}</$FeedName>\"\n\n            sed -i.bak \"s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|\" $ConfigFile\n        fi\n    done\nfi\n"
  },
  {
    "path": "eng/common/build.cmd",
    "content": "@echo off\npowershell -ExecutionPolicy ByPass -NoProfile -command \"& \"\"\"%~dp0build.ps1\"\"\" %*\"\nexit /b %ErrorLevel%\n"
  },
  {
    "path": "eng/common/build.ps1",
    "content": "[CmdletBinding(PositionalBinding=$false)]\nParam(\n  [string][Alias('c')]$configuration = \"Debug\",\n  [string]$platform = $null,\n  [string] $projects,\n  [string][Alias('v')]$verbosity = \"minimal\",\n  [string] $msbuildEngine = $null,\n  [bool] $warnAsError = $true,\n  [bool] $nodeReuse = $true,\n  [switch] $buildCheck = $false,\n  [switch][Alias('r')]$restore,\n  [switch] $deployDeps,\n  [switch][Alias('b')]$build,\n  [switch] $rebuild,\n  [switch] $deploy,\n  [switch][Alias('t')]$test,\n  [switch] $integrationTest,\n  [switch] $performanceTest,\n  [switch] $sign,\n  [switch] $pack,\n  [switch] $publish,\n  [switch] $clean,\n  [switch][Alias('pb')]$productBuild,\n  [switch]$fromVMR,\n  [switch][Alias('bl')]$binaryLog,\n  [switch][Alias('nobl')]$excludeCIBinarylog,\n  [switch] $ci,\n  [switch] $prepareMachine,\n  [string] $runtimeSourceFeed = '',\n  [string] $runtimeSourceFeedKey = '',\n  [switch] $excludePrereleaseVS,\n  [switch] $nativeToolsOnMachine,\n  [switch] $help,\n  [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties\n)\n\n# Unset 'Platform' environment variable to avoid unwanted collision in InstallDotNetCore.targets file\n# some computer has this env var defined (e.g. Some HP)\nif($env:Platform) {\n  $env:Platform=\"\"  \n}\nfunction Print-Usage() {\n  Write-Host \"Common settings:\"\n  Write-Host \"  -configuration <value>  Build configuration: 'Debug' or 'Release' (short: -c)\"\n  Write-Host \"  -platform <value>       Platform configuration: 'x86', 'x64' or any valid Platform value to pass to msbuild\"\n  Write-Host \"  -verbosity <value>      Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)\"\n  Write-Host \"  -binaryLog              Output binary log (short: -bl)\"\n  Write-Host \"  -help                   Print help and exit\"\n  Write-Host \"\"\n\n  Write-Host \"Actions:\"\n  Write-Host \"  -restore                Restore dependencies (short: -r)\"\n  Write-Host \"  -build                  Build solution (short: -b)\"\n  Write-Host \"  -rebuild                Rebuild solution\"\n  Write-Host \"  -deploy                 Deploy built VSIXes\"\n  Write-Host \"  -deployDeps             Deploy dependencies (e.g. VSIXes for integration tests)\"\n  Write-Host \"  -test                   Run all unit tests in the solution (short: -t)\"\n  Write-Host \"  -integrationTest        Run all integration tests in the solution\"\n  Write-Host \"  -performanceTest        Run all performance tests in the solution\"\n  Write-Host \"  -pack                   Package build outputs into NuGet packages and Willow components\"\n  Write-Host \"  -sign                   Sign build outputs\"\n  Write-Host \"  -publish                Publish artifacts (e.g. symbols)\"\n  Write-Host \"  -clean                  Clean the solution\"\n  Write-Host \"  -productBuild           Build the solution in the way it will be built in the full .NET product (VMR) build (short: -pb)\"\n  Write-Host \"\"\n\n  Write-Host \"Advanced settings:\"\n  Write-Host \"  -projects <value>       Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)\"\n  Write-Host \"  -ci                     Set when running on CI server\"\n  Write-Host \"  -excludeCIBinarylog     Don't output binary log (short: -nobl)\"\n  Write-Host \"  -prepareMachine         Prepare machine for CI run, clean up processes after build\"\n  Write-Host \"  -warnAsError <value>    Sets warnaserror msbuild parameter ('true' or 'false')\"\n  Write-Host \"  -msbuildEngine <value>  Msbuild engine to use to run build ('dotnet', 'vs', or unspecified).\"\n  Write-Host \"  -excludePrereleaseVS    Set to exclude build engines in prerelease versions of Visual Studio\"\n  Write-Host \"  -nativeToolsOnMachine   Sets the native tools on machine environment variable (indicating that the script should use native tools on machine)\"\n  Write-Host \"  -nodeReuse <value>      Sets nodereuse msbuild parameter ('true' or 'false')\"\n  Write-Host \"  -buildCheck             Sets /check msbuild parameter\"\n  Write-Host \"  -fromVMR                Set when building from within the VMR\"\n  Write-Host \"\"\n\n  Write-Host \"Command line arguments not listed above are passed thru to msbuild.\"\n  Write-Host \"The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.).\"\n}\n\n. $PSScriptRoot\\tools.ps1\n\nfunction InitializeCustomToolset {\n  if (-not $restore) {\n    return\n  }\n\n  $script = Join-Path $EngRoot 'restore-toolset.ps1'\n\n  if (Test-Path $script) {\n    . $script\n  }\n}\n\nfunction Build {\n  $toolsetBuildProj = InitializeToolset\n  InitializeCustomToolset\n\n  $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'Build.binlog') } else { '' }\n  $platformArg = if ($platform) { \"/p:Platform=$platform\" } else { '' }\n  $check = if ($buildCheck) { '/check' } else { '' }\n\n  if ($projects) {\n    # Re-assign properties to a new variable because PowerShell doesn't let us append properties directly for unclear reasons.\n    # Explicitly set the type as string[] because otherwise PowerShell would make this char[] if $properties is empty.\n    [string[]] $msbuildArgs = $properties\n    \n    # Resolve relative project paths into full paths \n    $projects = ($projects.Split(';').ForEach({Resolve-Path $_}) -join ';')\n    \n    $msbuildArgs += \"/p:Projects=$projects\"\n    $properties = $msbuildArgs\n  }\n\n  MSBuild $toolsetBuildProj `\n    $bl `\n    $platformArg `\n    $check `\n    /p:Configuration=$configuration `\n    /p:RepoRoot=$RepoRoot `\n    /p:Restore=$restore `\n    /p:DeployDeps=$deployDeps `\n    /p:Build=$build `\n    /p:Rebuild=$rebuild `\n    /p:Deploy=$deploy `\n    /p:Test=$test `\n    /p:Pack=$pack `\n    /p:DotNetBuild=$productBuild `\n    /p:DotNetBuildFromVMR=$fromVMR `\n    /p:IntegrationTest=$integrationTest `\n    /p:PerformanceTest=$performanceTest `\n    /p:Sign=$sign `\n    /p:Publish=$publish `\n    /p:RestoreStaticGraphEnableBinaryLogger=$binaryLog `\n    @properties\n}\n\ntry {\n  if ($clean) {\n    if (Test-Path $ArtifactsDir) {\n      Remove-Item -Recurse -Force $ArtifactsDir\n      Write-Host 'Artifacts directory deleted.'\n    }\n    exit 0\n  }\n\n  if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {\n    Print-Usage\n    exit 0\n  }\n\n  if ($ci) {\n    if (-not $excludeCIBinarylog) {\n      $binaryLog = $true\n    }\n    $nodeReuse = $false\n  }\n\n  if ($nativeToolsOnMachine) {\n    $env:NativeToolsOnMachine = $true\n  }\n  if ($restore) {\n    InitializeNativeTools\n  }\n\n  Build\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_\n  ExitWithExitCode 1\n}\n\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/build.sh",
    "content": "#!/usr/bin/env bash\n\n# Stop script if unbound variable found (use ${var:-} if intentional)\nset -u\n\n# Stop script if command returns non-zero exit code.\n# Prevents hidden errors caused by missing error code propagation.\nset -e\n\nusage()\n{\n  echo \"Common settings:\"\n  echo \"  --configuration <value>    Build configuration: 'Debug' or 'Release' (short: -c)\"\n  echo \"  --verbosity <value>        Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)\"\n  echo \"  --binaryLog                Create MSBuild binary log (short: -bl)\"\n  echo \"  --help                     Print help and exit (short: -h)\"\n  echo \"\"\n\n  echo \"Actions:\"\n  echo \"  --restore                  Restore dependencies (short: -r)\"\n  echo \"  --build                    Build solution (short: -b)\"\n  echo \"  --sourceBuild              Source-build the solution (short: -sb)\"\n  echo \"                             Will additionally trigger the following actions: --restore, --build, --pack\"\n  echo \"                             If --configuration is not set explicitly, will also set it to 'Release'\"\n  echo \"  --productBuild             Build the solution in the way it will be built in the full .NET product (VMR) build (short: -pb)\"\n  echo \"                             Will additionally trigger the following actions: --restore, --build, --pack\"\n  echo \"                             If --configuration is not set explicitly, will also set it to 'Release'\"\n  echo \"  --rebuild                  Rebuild solution\"\n  echo \"  --test                     Run all unit tests in the solution (short: -t)\"\n  echo \"  --integrationTest          Run all integration tests in the solution\"\n  echo \"  --performanceTest          Run all performance tests in the solution\"\n  echo \"  --pack                     Package build outputs into NuGet packages and Willow components\"\n  echo \"  --sign                     Sign build outputs\"\n  echo \"  --publish                  Publish artifacts (e.g. symbols)\"\n  echo \"  --clean                    Clean the solution\"\n  echo \"\"\n\n  echo \"Advanced settings:\"\n  echo \"  --projects <value>       Project or solution file(s) to build\"\n  echo \"  --ci                     Set when running on CI server\"\n  echo \"  --excludeCIBinarylog     Don't output binary log (short: -nobl)\"\n  echo \"  --prepareMachine         Prepare machine for CI run, clean up processes after build\"\n  echo \"  --nodeReuse <value>      Sets nodereuse msbuild parameter ('true' or 'false')\"\n  echo \"  --warnAsError <value>    Sets warnaserror msbuild parameter ('true' or 'false')\"\n  echo \"  --buildCheck <value>     Sets /check msbuild parameter\"\n  echo \"  --fromVMR                Set when building from within the VMR\"\n  echo \"\"\n  echo \"Command line arguments not listed above are passed thru to msbuild.\"\n  echo \"Arguments can also be passed in with a single hyphen.\"\n}\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nrestore=false\nbuild=false\nsource_build=false\nproduct_build=false\nfrom_vmr=false\nrebuild=false\ntest=false\nintegration_test=false\nperformance_test=false\npack=false\npublish=false\nsign=false\npublic=false\nci=false\nclean=false\n\nwarn_as_error=true\nnode_reuse=true\nbuild_check=false\nbinary_log=false\nexclude_ci_binary_log=false\npipelines_log=false\n\nprojects=''\nconfiguration=''\nprepare_machine=false\nverbosity='minimal'\nruntime_source_feed=''\nruntime_source_feed_key=''\n\nproperties=()\nwhile [[ $# > 0 ]]; do\n  opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n  case \"$opt\" in\n    -help|-h)\n      usage\n      exit 0\n      ;;\n    -clean)\n      clean=true\n      ;;\n    -configuration|-c)\n      configuration=$2\n      shift\n      ;;\n    -verbosity|-v)\n      verbosity=$2\n      shift\n      ;;\n    -binarylog|-bl)\n      binary_log=true\n      ;;\n    -excludecibinarylog|-nobl)\n      exclude_ci_binary_log=true\n      ;;\n    -pipelineslog|-pl)\n      pipelines_log=true\n      ;;\n    -restore|-r)\n      restore=true\n      ;;\n    -build|-b)\n      build=true\n      ;;\n    -rebuild)\n      rebuild=true\n      ;;\n    -pack)\n      pack=true\n      ;;\n    -sourcebuild|-source-build|-sb)\n      build=true\n      source_build=true\n      product_build=true\n      restore=true\n      pack=true\n      ;;\n    -productbuild|-product-build|-pb)\n      build=true\n      product_build=true\n      restore=true\n      pack=true\n      ;;\n    -fromvmr|-from-vmr)\n      from_vmr=true\n      ;;\n    -test|-t)\n      test=true\n      ;;\n    -integrationtest)\n      integration_test=true\n      ;;\n    -performancetest)\n      performance_test=true\n      ;;\n    -sign)\n      sign=true\n      ;;\n    -publish)\n      publish=true\n      ;;\n    -preparemachine)\n      prepare_machine=true\n      ;;\n    -projects)\n      projects=$2\n      shift\n      ;;\n    -ci)\n      ci=true\n      ;;\n    -warnaserror)\n      warn_as_error=$2\n      shift\n      ;;\n    -nodereuse)\n      node_reuse=$2\n      shift\n      ;;\n    -buildcheck)\n      build_check=true\n      ;;\n    -runtimesourcefeed)\n      runtime_source_feed=$2\n      shift\n      ;;\n     -runtimesourcefeedkey)\n      runtime_source_feed_key=$2\n      shift\n      ;;\n    *)\n      properties+=(\"$1\")\n      ;;\n  esac\n\n  shift\ndone\n\nif [[ -z \"$configuration\" ]]; then\n  if [[ \"$source_build\" = true ]]; then configuration=\"Release\"; else configuration=\"Debug\"; fi\nfi\n\nif [[ \"$ci\" == true ]]; then\n  pipelines_log=true\n  node_reuse=false\n  if [[ \"$exclude_ci_binary_log\" == false ]]; then\n    binary_log=true\n  fi\nfi\n\n. \"$scriptroot/tools.sh\"\n\nfunction InitializeCustomToolset {\n  local script=\"$eng_root/restore-toolset.sh\"\n\n  if [[ -a \"$script\" ]]; then\n    . \"$script\"\n  fi\n}\n\nfunction Build {\n  InitializeToolset\n  InitializeCustomToolset\n\n  if [[ ! -z \"$projects\" ]]; then\n    properties+=(\"/p:Projects=$projects\")\n  fi\n\n  local bl=\"\"\n  if [[ \"$binary_log\" == true ]]; then\n    bl=\"/bl:\\\"$log_dir/Build.binlog\\\"\"\n  fi\n\n  local check=\"\"\n  if [[ \"$build_check\" == true ]]; then\n    check=\"/check\"\n  fi\n\n  MSBuild $_InitializeToolset \\\n    $bl \\\n    $check \\\n    /p:Configuration=$configuration \\\n    /p:RepoRoot=\"$repo_root\" \\\n    /p:Restore=$restore \\\n    /p:Build=$build \\\n    /p:DotNetBuild=$product_build \\\n    /p:DotNetBuildSourceOnly=$source_build \\\n    /p:DotNetBuildFromVMR=$from_vmr \\\n    /p:Rebuild=$rebuild \\\n    /p:Test=$test \\\n    /p:Pack=$pack \\\n    /p:IntegrationTest=$integration_test \\\n    /p:PerformanceTest=$performance_test \\\n    /p:Sign=$sign \\\n    /p:Publish=$publish \\\n    /p:RestoreStaticGraphEnableBinaryLogger=$binary_log \\\n    ${properties[@]+\"${properties[@]}\"}\n\n  ExitWithExitCode 0\n}\n\nif [[ \"$clean\" == true ]]; then\n  if [ -d \"$artifacts_dir\" ]; then\n    rm -rf $artifacts_dir\n    echo \"Artifacts directory deleted.\"\n  fi\n  exit 0\nfi\n\nif [[ \"$restore\" == true ]]; then\n  InitializeNativeTools\nfi\n\nBuild\n"
  },
  {
    "path": "eng/common/cibuild.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $SOURCE until the file is no longer a symlink\nwhile [[ -h $source ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n\n  # if $source was a relative symlink, we need to resolve it relative to the path where \n  # the symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. \"$scriptroot/build.sh\" --restore --build --test --pack --publish --ci $@\n"
  },
  {
    "path": "eng/common/core-templates/job/job.yml",
    "content": "parameters:\n# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job\n  cancelTimeoutInMinutes: ''\n  condition: ''\n  container: ''\n  continueOnError: false\n  dependsOn: ''\n  displayName: ''\n  pool: ''\n  steps: []\n  strategy: ''\n  timeoutInMinutes: ''\n  variables: []\n  workspace: ''\n  templateContext: {}\n\n# Job base template specific parameters\n  # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md\n  # publishing defaults\n  artifacts: ''\n  enableMicrobuild: false\n  enableMicrobuildForMacAndLinux: false\n  microbuildUseESRP: true\n  enablePublishBuildArtifacts: false\n  enablePublishBuildAssets: false\n  enablePublishTestResults: false\n  enablePublishing: false\n  enableBuildRetry: false\n  mergeTestResults: false\n  testRunTitle: ''\n  testResultsFormat: ''\n  name: ''\n  preSteps: []\n  artifactPublishSteps: []\n  runAsPublic: false\n\n# 1es specific parameters\n  is1ESPipeline: ''\n\njobs:\n- job: ${{ parameters.name }}\n\n  ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}:\n    cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }}\n\n  ${{ if ne(parameters.condition, '') }}:\n    condition: ${{ parameters.condition }}\n\n  ${{ if ne(parameters.container, '') }}:\n    container: ${{ parameters.container }}\n\n  ${{ if ne(parameters.continueOnError, '') }}:\n    continueOnError: ${{ parameters.continueOnError }}\n\n  ${{ if ne(parameters.dependsOn, '') }}:\n    dependsOn: ${{ parameters.dependsOn }}\n\n  ${{ if ne(parameters.displayName, '') }}:\n    displayName: ${{ parameters.displayName }}\n\n  ${{ if ne(parameters.pool, '') }}:\n    pool: ${{ parameters.pool }}\n\n  ${{ if ne(parameters.strategy, '') }}:\n    strategy: ${{ parameters.strategy }}\n\n  ${{ if ne(parameters.timeoutInMinutes, '') }}:\n    timeoutInMinutes: ${{ parameters.timeoutInMinutes }}\n\n  ${{ if ne(parameters.templateContext, '') }}:\n    templateContext: ${{ parameters.templateContext }}\n\n  variables:\n  - ${{ if ne(parameters.enableTelemetry, 'false') }}:\n    - name: DOTNET_CLI_TELEMETRY_PROFILE\n      value: '$(Build.Repository.Uri)'\n  # Retry signature validation up to three times, waiting 2 seconds between attempts.\n  # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures\n  - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY\n    value: 3,2000\n  - ${{ each variable in parameters.variables }}:\n    # handle name-value variable syntax\n    # example:\n    # - name: [key]\n    #   value: [value]\n    - ${{ if ne(variable.name, '') }}:\n      - name: ${{ variable.name }}\n        value: ${{ variable.value }}\n\n    # handle variable groups\n    - ${{ if ne(variable.group, '') }}:\n      - group: ${{ variable.group }}\n\n    # handle template variable syntax\n    # example:\n    # - template: path/to/template.yml\n    #   parameters:\n    #     [key]: [value]\n    - ${{ if ne(variable.template, '') }}:\n      - template: ${{ variable.template }}\n        ${{ if ne(variable.parameters, '') }}:\n          parameters: ${{ variable.parameters }}\n\n    # handle key-value variable syntax.\n    # example:\n    # - [key]: [value]\n    - ${{ if and(eq(variable.name, ''), eq(variable.group, ''), eq(variable.template, '')) }}:\n      - ${{ each pair in variable }}:\n        - name: ${{ pair.key }}\n          value: ${{ pair.value }}\n\n  # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds\n  - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n    - group: DotNet-HelixApi-Access\n\n  ${{ if ne(parameters.workspace, '') }}:\n    workspace: ${{ parameters.workspace }}\n\n  steps:\n  - ${{ if eq(parameters.is1ESPipeline, '') }}:\n    - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n  - ${{ if ne(parameters.preSteps, '') }}:\n    - ${{ each preStep in parameters.preSteps }}:\n      - ${{ preStep }}\n\n  - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n    - template: /eng/common/core-templates/steps/install-microbuild.yml\n      parameters:\n        enableMicrobuild: ${{ parameters.enableMicrobuild }}\n        enableMicrobuildForMacAndLinux: ${{ parameters.enableMicrobuildForMacAndLinux }}\n        microbuildUseESRP: ${{ parameters.microbuildUseESRP }}\n        continueOnError: ${{ parameters.continueOnError }}\n\n  - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}:\n    - task: NuGetAuthenticate@1\n\n  - ${{ if and(ne(parameters.artifacts.download, 'false'), ne(parameters.artifacts.download, '')) }}:\n    - task: DownloadPipelineArtifact@2\n      inputs:\n        buildType: current\n        artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }}\n        targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }}\n        itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }}\n\n  - ${{ each step in parameters.steps }}:\n    - ${{ step }}\n\n  - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n    - template: /eng/common/core-templates/steps/cleanup-microbuild.yml\n      parameters:\n        enableMicrobuild: ${{ parameters.enableMicrobuild }}\n        enableMicrobuildForMacAndLinux: ${{ parameters.enableMicrobuildForMacAndLinux }}\n        continueOnError: ${{ parameters.continueOnError }}\n\n  # Publish test results\n  - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}:\n    - task: PublishTestResults@2\n      displayName: Publish XUnit Test Results\n      inputs:\n        testResultsFormat: 'xUnit'\n        testResultsFiles: '*.xml'\n        searchFolder: '$(System.DefaultWorkingDirectory)/artifacts/TestResults/$(_BuildConfig)'\n        testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit\n        mergeTestResults: ${{ parameters.mergeTestResults }}\n      continueOnError: true\n      condition: always()\n  - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}:\n    - task: PublishTestResults@2\n      displayName: Publish TRX Test Results\n      inputs:\n        testResultsFormat: 'VSTest'\n        testResultsFiles: '*.trx'\n        searchFolder: '$(System.DefaultWorkingDirectory)/artifacts/TestResults/$(_BuildConfig)'\n        testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx\n        mergeTestResults: ${{ parameters.mergeTestResults }}\n      continueOnError: true\n      condition: always()\n\n  # gather artifacts\n  - ${{ if ne(parameters.artifacts.publish, '') }}:\n    - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}:\n      - task: CopyFiles@2\n        displayName: Gather binaries for publish to artifacts\n        inputs:\n          SourceFolder: 'artifacts/bin'\n          Contents: '**'\n          TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin'\n      - task: CopyFiles@2\n        displayName: Gather packages for publish to artifacts\n        inputs:\n          SourceFolder: 'artifacts/packages'\n          Contents: '**'\n          TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages'\n    - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}:\n      - task: CopyFiles@2\n        displayName: Gather logs for publish to artifacts\n        inputs:\n          SourceFolder: 'artifacts/log'\n          Contents: '**'\n          TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/log'\n        continueOnError: true\n        condition: always()\n      \n  - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:\n    - task: CopyFiles@2\n      displayName: Gather logs for publish to artifacts\n      inputs:\n        SourceFolder: 'artifacts/log/$(_BuildConfig)'\n        Contents: '**'\n        TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)'\n      continueOnError: true\n      condition: always()\n  - ${{ if eq(parameters.enableBuildRetry, 'true') }}:\n    - task: CopyFiles@2\n      displayName: Gather buildconfiguration for build retry\n      inputs:\n        SourceFolder: '$(System.DefaultWorkingDirectory)/eng/common/BuildConfiguration'\n        Contents: '**'\n        TargetFolder: '$(Build.ArtifactStagingDirectory)/eng/common/BuildConfiguration'\n      continueOnError: true\n      condition: always()\n  - ${{ each step in parameters.artifactPublishSteps }}:\n    - ${{ step }}\n"
  },
  {
    "path": "eng/common/core-templates/job/onelocbuild.yml",
    "content": "parameters:\n  # Optional: dependencies of the job\n  dependsOn: ''\n\n  # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool\n  pool: ''\n\n  CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex\n  GithubPat: $(BotAccount-dotnet-bot-repo-PAT)\n\n  SourcesDirectory: $(System.DefaultWorkingDirectory)\n  CreatePr: true\n  AutoCompletePr: false\n  ReusePr: true\n  UseLfLineEndings: true\n  UseCheckedInLocProjectJson: false\n  SkipLocProjectJsonGeneration: false\n  LanguageSet: VS_Main_Languages\n  LclSource: lclFilesInRepo\n  LclPackageId: ''\n  RepoType: gitHub\n  GitHubOrg: dotnet\n  MirrorRepo: ''\n  MirrorBranch: main\n  condition: ''\n  JobNameSuffix: ''\n  is1ESPipeline: ''\njobs:\n- job: OneLocBuild${{ parameters.JobNameSuffix }}\n\n  dependsOn: ${{ parameters.dependsOn }}\n\n  displayName: OneLocBuild${{ parameters.JobNameSuffix }}\n\n  variables:\n    - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat\n    - name: _GenerateLocProjectArguments\n      value: -SourcesDirectory ${{ parameters.SourcesDirectory }}\n        -LanguageSet \"${{ parameters.LanguageSet }}\"\n        -CreateNeutralXlfs\n    - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}:\n      - name: _GenerateLocProjectArguments\n        value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson\n    - template: /eng/common/core-templates/variables/pool-providers.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n  ${{ if ne(parameters.pool, '') }}:\n    pool: ${{ parameters.pool }}\n  ${{ if eq(parameters.pool, '') }}:\n    pool:\n      # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n      ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n        name: AzurePipelines-EO\n        image: 1ESPT-Windows2025\n        demands: Cmd\n        os: windows\n      # If it's not devdiv, it's dnceng\n      ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:\n        name: $(DncEngInternalBuildPool)\n        image: windows.vs2026.amd64\n        os: windows\n\n  steps:\n    - ${{ if eq(parameters.is1ESPipeline, '') }}:\n      - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n    - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}:\n      - task: Powershell@2\n        inputs:\n          filePath: $(System.DefaultWorkingDirectory)/eng/common/generate-locproject.ps1\n          arguments: $(_GenerateLocProjectArguments)\n        displayName: Generate LocProject.json\n        condition: ${{ parameters.condition }}\n\n    - task: OneLocBuild@2\n      displayName: OneLocBuild\n      env:\n        SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n      inputs:\n        locProj: eng/Localize/LocProject.json\n        outDir: $(Build.ArtifactStagingDirectory)\n        lclSource: ${{ parameters.LclSource }}\n        lclPackageId: ${{ parameters.LclPackageId }}\n        isCreatePrSelected: ${{ parameters.CreatePr }}\n        isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}\n        ${{ if eq(parameters.CreatePr, true) }}:\n          isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}\n          isShouldReusePrSelected: ${{ parameters.ReusePr }}\n        packageSourceAuth: patAuth\n        patVariable: ${{ parameters.CeapexPat }}\n        ${{ if eq(parameters.RepoType, 'gitHub') }}:\n          repoType: ${{ parameters.RepoType }}\n          gitHubPatVariable: \"${{ parameters.GithubPat }}\"\n        ${{ if ne(parameters.MirrorRepo, '') }}:\n          isMirrorRepoSelected: true\n          gitHubOrganization: ${{ parameters.GitHubOrg }}\n          mirrorRepo: ${{ parameters.MirrorRepo }}\n          mirrorBranch: ${{ parameters.MirrorBranch }}\n      condition: ${{ parameters.condition }}\n\n    # Copy the locProject.json to the root of the Loc directory, then publish a pipeline artifact\n    - task: CopyFiles@2\n      displayName: Copy LocProject.json\n      inputs:\n        SourceFolder: '$(System.DefaultWorkingDirectory)/eng/Localize/'\n        Contents: 'LocProject.json'\n        TargetFolder: '$(Build.ArtifactStagingDirectory)/loc'\n      condition: ${{ parameters.condition }}\n\n    - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n        args:\n          targetPath: '$(Build.ArtifactStagingDirectory)/loc'\n          artifactName: 'Loc'\n          displayName: 'Publish Localization Files'\n          condition: ${{ parameters.condition }}\n"
  },
  {
    "path": "eng/common/core-templates/job/publish-build-assets.yml",
    "content": "parameters:\n  configuration: 'Debug'\n\n  # Optional: condition for the job to run\n  condition: ''\n\n  # Optional: 'true' if future jobs should run even if this job fails\n  continueOnError: false\n\n  # Optional: dependencies of the job\n  dependsOn: ''\n\n  # Optional: Include PublishBuildArtifacts task\n  enablePublishBuildArtifacts: false\n\n  # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool\n  pool: {}\n\n  # Optional: should run as a public build even in the internal project\n  #           if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.\n  runAsPublic: false\n\n  # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing\n  publishAssetsImmediately: false\n\n  artifactsPublishingAdditionalParameters: ''\n\n  signingValidationAdditionalParameters: ''\n\n  is1ESPipeline: ''\n\n  # Optional: 🌤️ or not the build has assets it wants to publish to BAR\n  isAssetlessBuild: false\n\n  # Optional, publishing version\n  publishingVersion: 3\n\n  # Optional: A minimatch pattern for the asset manifests to publish to BAR\n  assetManifestsPattern: '*/manifests/**/*.xml'\n\n  repositoryAlias: self\n\n  officialBuildId: ''\n\njobs:\n- job: Asset_Registry_Publish\n\n  dependsOn: ${{ parameters.dependsOn }}\n  timeoutInMinutes: 150\n\n  ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:\n    displayName: Publish Assets\n  ${{ else }}:\n    displayName: Publish to Build Asset Registry\n\n  variables:\n  - template: /eng/common/core-templates/variables/pool-providers.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n  - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n    - group: Publish-Build-Assets\n    - group: AzureDevOps-Artifact-Feeds-Pats\n    - name: runCodesignValidationInjection\n      value: false\n    # unconditional - needed for logs publishing (redactor tool version)\n    - template: /eng/common/core-templates/post-build/common-variables.yml\n  - name: OfficialBuildId\n    ${{ if ne(parameters.officialBuildId, '') }}:\n      value: ${{ parameters.officialBuildId }}\n    ${{ else }}:\n      value: $(Build.BuildNumber)\n\n  pool:\n    # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n    ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n      name: AzurePipelines-EO\n      image: 1ESPT-Windows2025\n      demands: Cmd\n      os: windows\n    # If it's not devdiv, it's dnceng\n    ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:\n      name: NetCore1ESPool-Publishing-Internal\n      image: windows.vs2026.amd64\n      os: windows\n  steps:\n  - ${{ if eq(parameters.is1ESPipeline, '') }}:\n    - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n  - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n    - checkout: ${{ parameters.repositoryAlias }}\n      fetchDepth: 3\n      clean: true\n\n    - ${{ if eq(parameters.isAssetlessBuild, 'false') }}: \n      - ${{ if eq(parameters.publishingVersion, 3) }}: \n        - task: DownloadPipelineArtifact@2\n          displayName: Download Asset Manifests\n          inputs:\n            artifactName: AssetManifests\n            targetPath: '$(Build.StagingDirectory)/AssetManifests'\n          condition: ${{ parameters.condition }}\n          continueOnError: ${{ parameters.continueOnError }}\n      - ${{ if eq(parameters.publishingVersion, 4) }}:\n        - task: DownloadPipelineArtifact@2\n          displayName: Download V4 asset manifests\n          inputs:\n            itemPattern: '*/manifests/**/*.xml'\n            targetPath: '$(Build.StagingDirectory)/AllAssetManifests'\n          condition: ${{ parameters.condition }}\n          continueOnError: ${{ parameters.continueOnError }}\n        - task: CopyFiles@2\n          displayName: Copy V4 asset manifests to AssetManifests\n          inputs:\n            SourceFolder: '$(Build.StagingDirectory)/AllAssetManifests'\n            Contents: ${{ parameters.assetManifestsPattern }}\n            TargetFolder: '$(Build.StagingDirectory)/AssetManifests'\n            flattenFolders: true\n          condition: ${{ parameters.condition }}\n          continueOnError: ${{ parameters.continueOnError }}\n    \n    - task: NuGetAuthenticate@1\n\n    # Populate internal runtime variables.\n    - template: /eng/common/templates/steps/enable-internal-sources.yml\n      ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n        parameters:\n            legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw)\n    \n    - template: /eng/common/templates/steps/enable-internal-runtimes.yml\n\n    - task: AzureCLI@2\n      displayName: Publish Build Assets\n      inputs:\n        azureSubscription: \"Darc: Maestro Production\"\n        scriptType: ps\n        scriptLocation: scriptPath\n        scriptPath: $(System.DefaultWorkingDirectory)/eng/common/sdk-task.ps1\n        arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet\n          /p:ManifestsPath='$(Build.StagingDirectory)/AssetManifests'\n          /p:IsAssetlessBuild=${{ parameters.isAssetlessBuild }}\n          /p:MaestroApiEndpoint=https://maestro.dot.net\n          /p:OfficialBuildId=$(OfficialBuildId)\n          -runtimeSourceFeed https://ci.dot.net/internal\n          -runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)'\n\n      condition: ${{ parameters.condition }}\n      continueOnError: ${{ parameters.continueOnError }}\n    \n    - task: powershell@2\n      displayName: Create ReleaseConfigs Artifact\n      inputs:\n        targetType: inline\n        script: |\n          New-Item -Path \"$(Build.StagingDirectory)/ReleaseConfigs\" -ItemType Directory -Force\n          $filePath = \"$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt\"\n          Add-Content -Path $filePath -Value $(BARBuildId)\n          Add-Content -Path $filePath -Value \"$(DefaultChannels)\"\n          Add-Content -Path $filePath -Value $(IsStableBuild)\n\n          $symbolExclusionfile = \"$(System.DefaultWorkingDirectory)/eng/SymbolPublishingExclusionsFile.txt\"\n          if (Test-Path -Path $symbolExclusionfile)\n          {\n            Write-Host \"SymbolExclusionFile exists\"\n            Copy-Item -Path $symbolExclusionfile -Destination \"$(Build.StagingDirectory)/ReleaseConfigs\"\n          }\n\n    - ${{ if eq(parameters.publishingVersion, 4) }}:\n      - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n        parameters:\n          is1ESPipeline: ${{ parameters.is1ESPipeline }}\n          args:\n            targetPath: '$(Build.ArtifactStagingDirectory)/MergedManifest.xml'\n            artifactName: AssetManifests\n            displayName: 'Publish Merged Manifest'\n            retryCountOnTaskFailure: 10 # for any files being locked\n            isProduction: false # just metadata for publishing\n\n    - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n        args:\n          displayName: Publish ReleaseConfigs Artifact\n          targetPath: '$(Build.StagingDirectory)/ReleaseConfigs'\n          artifactName: ReleaseConfigs\n          retryCountOnTaskFailure: 10 # for any files being locked\n          isProduction: false # just metadata for publishing\n\n    - ${{ if or(eq(parameters.publishAssetsImmediately, 'true'), eq(parameters.isAssetlessBuild, 'true')) }}:\n      - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n        parameters:\n          BARBuildId: ${{ parameters.BARBuildId }}\n          PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}\n          is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n      # Darc is targeting 8.0, so make sure it's installed\n      - task: UseDotNet@2\n        inputs:\n          version: 8.0.x\n\n      - task: AzureCLI@2\n        displayName: Publish Using Darc\n        inputs:\n          azureSubscription: \"Darc: Maestro Production\"\n          scriptType: ps\n          scriptLocation: scriptPath\n          scriptPath: $(System.DefaultWorkingDirectory)/eng/common/post-build/publish-using-darc.ps1\n          arguments: >\n            -BuildId $(BARBuildId)\n            -PublishingInfraVersion 3\n            -AzdoToken '$(System.AccessToken)'\n            -WaitPublishingFinish true\n            -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'\n            -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'\n            -SkipAssetsPublishing '${{ parameters.isAssetlessBuild }}'\n            -runtimeSourceFeed https://ci.dot.net/internal\n            -runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)'\n\n    - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:\n      - template: /eng/common/core-templates/steps/publish-logs.yml\n        parameters:\n          is1ESPipeline: ${{ parameters.is1ESPipeline }}\n          StageLabel: 'BuildAssetRegistry'\n          JobLabel: 'Publish_Artifacts_Logs'\n"
  },
  {
    "path": "eng/common/core-templates/job/source-build.yml",
    "content": "parameters:\n  # This template adds arcade-powered source-build to CI. The template produces a server job with a\n  # default ID 'Source_Build_Complete' to put in a dependency list if necessary.\n\n  # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed.\n  jobNamePrefix: 'Source_Build'\n\n  # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for\n  # managed-only repositories. This is an object with these properties:\n  #\n  # name: ''\n  #   The name of the job. This is included in the job ID.\n  # targetRID: ''\n  #   The name of the target RID to use, instead of the one auto-detected by Arcade.\n  # portableBuild: false\n  #   Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than\n  #   linux-x64), and compiling against distro-provided packages rather than portable ones. The\n  #   default is portable mode.\n  # skipPublishValidation: false\n  #   Disables publishing validation.  By default, a check is performed to ensure no packages are\n  #   published by source-build.\n  # container: ''\n  #   A container to use. Runs in docker.\n  # pool: {}\n  #   A pool to use. Runs directly on an agent.\n  # buildScript: ''\n  #   Specifies the build script to invoke to perform the build in the repo. The default\n  #   './build.sh' should work for typical Arcade repositories, but this is customizable for\n  #   difficult situations.\n  # buildArguments: ''\n  #   Specifies additional build arguments to pass to the build script.\n  # jobProperties: {}\n  #   A list of job properties to inject at the top level, for potential extensibility beyond\n  #   container and pool.\n  platform: {}\n\n  is1ESPipeline: ''\n\n  # If set to true and running on a non-public project,\n  # Internal nuget and blob storage locations will be enabled.\n  # This is not enabled by default because many repositories do not need internal sources\n  # and do not need to have the required service connections approved in the pipeline.\n  enableInternalSources: false\n\njobs:\n- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}\n  displayName: Source-Build (${{ parameters.platform.name }})\n\n  ${{ each property in parameters.platform.jobProperties }}:\n    ${{ property.key }}: ${{ property.value }}\n\n  ${{ if ne(parameters.platform.container, '') }}:\n    container: ${{ parameters.platform.container }}\n\n  ${{ if eq(parameters.platform.pool, '') }}:\n    # The default VM host AzDO pool. This should be capable of running Docker containers: almost all\n    # source-build builds run in Docker, including the default managed platform.\n    # /eng/common/core-templates/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic\n    ${{ if eq(parameters.is1ESPipeline, 'true') }}:\n      pool:\n        ${{ if eq(variables['System.TeamProject'], 'public') }}:\n          name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')]\n          demands: ImageOverride -equals build.azurelinux.3.amd64.open\n        ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n          name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')]\n          image: build.azurelinux.3.amd64\n          os: linux\n    ${{ else }}:\n      pool:\n        ${{ if eq(variables['System.TeamProject'], 'public') }}:\n          name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')]\n          demands: ImageOverride -equals build.azurelinux.3.amd64.open\n        ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n          name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')]\n          demands: ImageOverride -equals build.azurelinux.3.amd64\n  ${{ if ne(parameters.platform.pool, '') }}:\n    pool: ${{ parameters.platform.pool }}\n\n  workspace:\n    clean: all\n\n  steps:\n  - ${{ if eq(parameters.is1ESPipeline, '') }}:\n    - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n  - ${{ if eq(parameters.enableInternalSources, true) }}:\n    - template: /eng/common/core-templates/steps/enable-internal-sources.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    - template: /eng/common/core-templates/steps/enable-internal-runtimes.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n  - template: /eng/common/core-templates/steps/source-build.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      platform: ${{ parameters.platform }}\n"
  },
  {
    "path": "eng/common/core-templates/job/source-index-stage1.yml",
    "content": "parameters:\n  runAsPublic: false\n  sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command \"eng/common/build.ps1 -restore -build -binarylog -ci\"\n  preSteps: []\n  binlogPath: artifacts/log/Debug/Build.binlog\n  condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')\n  dependsOn: ''\n  pool: ''\n  is1ESPipeline: ''\n\njobs:\n- job: SourceIndexStage1\n  dependsOn: ${{ parameters.dependsOn }}\n  condition: ${{ parameters.condition }}\n  variables:\n  - name: BinlogPath\n    value: ${{ parameters.binlogPath }}\n  - template: /eng/common/core-templates/variables/pool-providers.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n  ${{ if ne(parameters.pool, '') }}:\n    pool: ${{ parameters.pool }}\n  ${{ if eq(parameters.pool, '') }}:\n    pool:\n      ${{ if eq(variables['System.TeamProject'], 'public') }}:\n        name: $(DncEngPublicBuildPool)\n        image: windows.vs2026preview.scout.amd64.open\n      ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n        name: $(DncEngInternalBuildPool)\n        image: windows.vs2026preview.scout.amd64\n\n  steps:\n  - ${{ if eq(parameters.is1ESPipeline, '') }}:\n    - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n  - ${{ each preStep in parameters.preSteps }}:\n    - ${{ preStep }}\n  - script: ${{ parameters.sourceIndexBuildCommand }}\n    displayName: Build Repository\n\n  - template: /eng/common/core-templates/steps/source-index-stage1-publish.yml\n    parameters:\n      binLogPath: ${{ parameters.binLogPath }}\n"
  },
  {
    "path": "eng/common/core-templates/jobs/codeql-build.yml",
    "content": "parameters:\n  # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md\n  continueOnError: false\n  # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job\n  jobs: []\n  # Optional: if specified, restore and use this version of Guardian instead of the default.\n  overrideGuardianVersion: ''\n  is1ESPipeline: ''\n\njobs:\n- template: /eng/common/core-templates/jobs/jobs.yml\n  parameters:\n    is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    enableMicrobuild: false\n    enablePublishBuildArtifacts: false\n    enablePublishTestResults: false\n    enablePublishBuildAssets: false\n    enableTelemetry: true\n\n    variables:\n      - group: Publish-Build-Assets\n      # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in\n      # sync with the packages.config file.\n      - name: DefaultGuardianVersion\n        value: 0.109.0\n      - name: GuardianPackagesConfigFile\n        value: $(System.DefaultWorkingDirectory)\\eng\\common\\sdl\\packages.config\n      - name: GuardianVersion\n        value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }}\n  \n    jobs: ${{ parameters.jobs }}\n        \n"
  },
  {
    "path": "eng/common/core-templates/jobs/jobs.yml",
    "content": "parameters:\n  # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md\n  continueOnError: false\n\n  # Optional: Include PublishBuildArtifacts task\n  enablePublishBuildArtifacts: false\n\n  # Optional: Enable running the source-build jobs to build repo from source\n  enableSourceBuild: false\n\n  # Optional: Parameters for source-build template.\n  #           See /eng/common/core-templates/jobs/source-build.yml for options\n  sourceBuildParameters: []\n\n  graphFileGeneration:\n    # Optional: Enable generating the graph files at the end of the build\n    enabled: false\n    # Optional: Include toolset dependencies in the generated graph files\n    includeToolset: false\n    \n  # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job\n  jobs: []\n\n  # Optional: Override automatically derived dependsOn value for \"publish build assets\" job\n  publishBuildAssetsDependsOn: ''\n\n  # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage.\n  publishAssetsImmediately: false\n\n  # Optional: 🌤️ or not the build has assets it wants to publish to BAR\n  isAssetlessBuild: false\n\n  # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml)\n  artifactsPublishingAdditionalParameters: ''\n  signingValidationAdditionalParameters: ''\n\n  # Optional: should run as a public build even in the internal project\n  #           if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.\n  runAsPublic: false\n\n  enableSourceIndex: false\n  sourceIndexParams: {}\n\n  artifacts: {}\n  is1ESPipeline: ''\n\n  # Publishing version w/default.\n  publishingVersion: 3\n\n  repositoryAlias: self\n  officialBuildId: ''\n\n# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,\n# and some (Microbuild) should only be applied to non-PR cases for internal builds.\n\njobs:\n- ${{ each job in parameters.jobs }}:\n  - ${{ if eq(parameters.is1ESPipeline, 'true') }}:\n    - template: /eng/common/templates-official/job/job.yml\n      parameters: \n        # pass along parameters\n        ${{ each parameter in parameters }}:\n          ${{ if ne(parameter.key, 'jobs') }}:\n            ${{ parameter.key }}: ${{ parameter.value }}\n\n        # pass along job properties\n        ${{ each property in job }}:\n          ${{ if ne(property.key, 'job') }}:\n            ${{ property.key }}: ${{ property.value }}\n\n        name: ${{ job.job }}\n\n  - ${{ else }}:\n    - template: /eng/common/templates/job/job.yml\n      parameters: \n        # pass along parameters\n        ${{ each parameter in parameters }}:\n          ${{ if ne(parameter.key, 'jobs') }}:\n            ${{ parameter.key }}: ${{ parameter.value }}\n\n        # pass along job properties\n        ${{ each property in job }}:\n          ${{ if ne(property.key, 'job') }}:\n            ${{ property.key }}: ${{ property.value }}\n\n        name: ${{ job.job }}\n\n- ${{ if eq(parameters.enableSourceBuild, true) }}:\n  - template: /eng/common/core-templates/jobs/source-build.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      ${{ each parameter in parameters.sourceBuildParameters }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n\n- ${{ if eq(parameters.enableSourceIndex, 'true') }}:\n  - template: ../job/source-index-stage1.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      runAsPublic: ${{ parameters.runAsPublic }}\n      ${{ each parameter in parameters.sourceIndexParams }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n\n- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n  - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, ''), eq(parameters.isAssetlessBuild, true)) }}:\n    - template: ../job/publish-build-assets.yml\n      parameters:\n        is1ESPipeline: ${{ parameters.is1ESPipeline }}\n        continueOnError: ${{ parameters.continueOnError }}\n        publishingVersion: ${{ parameters.publishingVersion }}\n        dependsOn:\n        - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}:\n          - ${{ each job in parameters.publishBuildAssetsDependsOn }}:\n            - ${{ job.job }}\n        - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:\n          - ${{ each job in parameters.jobs }}:\n            - ${{ job.job }}\n\n        runAsPublic: ${{ parameters.runAsPublic }}\n        publishAssetsImmediately: ${{ or(parameters.publishAssetsImmediately, parameters.isAssetlessBuild) }}\n        isAssetlessBuild: ${{ parameters.isAssetlessBuild }}\n        enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}\n        artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}\n        signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }}\n        repositoryAlias: ${{ parameters.repositoryAlias }}\n        officialBuildId: ${{ parameters.officialBuildId }}\n"
  },
  {
    "path": "eng/common/core-templates/jobs/source-build.yml",
    "content": "parameters:\n  # This template adds arcade-powered source-build to CI. A job is created for each platform, as\n  # well as an optional server job that completes when all platform jobs complete.\n\n  # See /eng/common/core-templates/job/source-build.yml\n  jobNamePrefix: 'Source_Build'\n\n  # This is the default platform provided by Arcade, intended for use by a managed-only repo.\n  defaultManagedPlatform:\n    name: 'Managed'\n    container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64'\n\n  # Defines the platforms on which to run build jobs. One job is created for each platform, and the\n  # object in this array is sent to the job template as 'platform'. If no platforms are specified,\n  # one job runs on 'defaultManagedPlatform'.\n  platforms: []\n\n  is1ESPipeline: ''\n\n  # If set to true and running on a non-public project,\n  # Internal nuget and blob storage locations will be enabled.\n  # This is not enabled by default because many repositories do not need internal sources\n  # and do not need to have the required service connections approved in the pipeline.\n  enableInternalSources: false\n\njobs:\n\n- ${{ each platform in parameters.platforms }}:\n  - template: /eng/common/core-templates/job/source-build.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      jobNamePrefix: ${{ parameters.jobNamePrefix }}\n      platform: ${{ platform }}\n      enableInternalSources: ${{ parameters.enableInternalSources }}\n\n- ${{ if eq(length(parameters.platforms), 0) }}:\n  - template: /eng/common/core-templates/job/source-build.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      jobNamePrefix: ${{ parameters.jobNamePrefix }}\n      platform: ${{ parameters.defaultManagedPlatform }}\n      enableInternalSources: ${{ parameters.enableInternalSources }}\n"
  },
  {
    "path": "eng/common/core-templates/post-build/common-variables.yml",
    "content": "variables:\n  - group: Publish-Build-Assets\n\n  # Whether the build is internal or not\n  - name: IsInternalBuild\n    value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }}\n\n  # Default Maestro++ API Endpoint and API Version\n  - name: MaestroApiEndPoint\n    value: \"https://maestro.dot.net\"\n  - name: MaestroApiVersion\n    value: \"2020-02-20\"\n\n  - name: SourceLinkCLIVersion\n    value: 3.0.0\n  - name: SymbolToolVersion\n    value: 1.0.1\n  - name: BinlogToolVersion\n    value: 1.0.11\n\n  - name: runCodesignValidationInjection\n    value: false\n"
  },
  {
    "path": "eng/common/core-templates/post-build/post-build.yml",
    "content": "parameters:\n  # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST.\n  # Publishing V1 is no longer supported\n  # Publishing V2 is no longer supported\n  # Publishing V3 is the default\n  - name: publishingInfraVersion\n    displayName: Which version of publishing should be used to promote the build definition?\n    type: number\n    default: 3\n    values:\n    - 3\n    - 4\n\n  - name: BARBuildId\n    displayName: BAR Build Id\n    type: number\n    default: 0\n\n  - name: PromoteToChannelIds\n    displayName: Channel to promote BARBuildId to\n    type: string\n    default: ''\n\n  - name: enableSourceLinkValidation\n    displayName: Enable SourceLink validation\n    type: boolean\n    default: false\n\n  - name: enableSigningValidation\n    displayName: Enable signing validation\n    type: boolean\n    default: true\n\n  - name: enableSymbolValidation\n    displayName: Enable symbol validation\n    type: boolean\n    default: false\n\n  - name: enableNugetValidation\n    displayName: Enable NuGet validation\n    type: boolean\n    default: true\n    \n  - name: publishInstallersAndChecksums\n    displayName: Publish installers and checksums\n    type: boolean\n    default: true\n    \n  - name: requireDefaultChannels\n    displayName: Fail the build if there are no default channel(s) registrations for the current build\n    type: boolean\n    default: false\n\n  - name: SDLValidationParameters\n    type: object\n    default:\n      enable: false\n      publishGdn: false\n      continueOnError: false\n      params: ''\n      artifactNames: ''\n      downloadArtifacts: true\n\n  - name: isAssetlessBuild\n    type: boolean\n    displayName: Is Assetless Build\n    default: false\n\n  # These parameters let the user customize the call to sdk-task.ps1 for publishing\n  # symbols & general artifacts as well as for signing validation\n  - name: symbolPublishingAdditionalParameters\n    displayName: Symbol publishing additional parameters\n    type: string\n    default: ''\n\n  - name: artifactsPublishingAdditionalParameters\n    displayName: Artifact publishing additional parameters\n    type: string\n    default: ''\n\n  - name: signingValidationAdditionalParameters\n    displayName: Signing validation additional parameters\n    type: string\n    default: ''\n\n  # Which stages should finish execution before post-build stages start\n  - name: validateDependsOn\n    type: object\n    default:\n    - build\n\n  - name: publishDependsOn\n    type: object\n    default:\n    - Validate\n\n  # Optional: Call asset publishing rather than running in a separate stage\n  - name: publishAssetsImmediately\n    type: boolean\n    default: false\n\n  - name: is1ESPipeline\n    type: boolean\n    default: false\n\nstages:\n- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:\n  - stage: Validate\n    dependsOn: ${{ parameters.validateDependsOn }}\n    displayName: Validate Build Assets\n    variables:\n      - template: /eng/common/core-templates/post-build/common-variables.yml\n      - template: /eng/common/core-templates/variables/pool-providers.yml\n        parameters:\n          is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    jobs:\n    - job:\n      displayName: NuGet Validation\n      condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true'))\n      pool:\n        # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n        ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n          name: AzurePipelines-EO\n          image: 1ESPT-Windows2025\n          demands: Cmd\n          os: windows\n        # If it's not devdiv, it's dnceng\n        ${{ else }}:\n          ${{ if eq(parameters.is1ESPipeline, true) }}:\n            name: $(DncEngInternalBuildPool)\n            image: windows.vs2026preview.scout.amd64\n            os: windows\n          ${{ else }}:\n            name: $(DncEngInternalBuildPool)\n            demands: ImageOverride -equals windows.vs2026preview.scout.amd64\n\n      steps:\n        - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n          parameters:\n            BARBuildId: ${{ parameters.BARBuildId }}\n            PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}\n            is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n        - ${{ if ne(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadBuildArtifacts@0\n            displayName: Download Package Artifacts\n            inputs:\n              buildType: specific\n              buildVersionToDownload: specific\n              project: $(AzDOProjectName)\n              pipeline: $(AzDOPipelineId)\n              buildId: $(AzDOBuildId)\n              artifactName: PackageArtifacts\n              checkDownloadedFiles: true\n        - ${{ if eq(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadPipelineArtifact@2\n            displayName: Download Pipeline Artifacts (V4)\n            inputs:\n              itemPattern: '*/packages/**/*.nupkg'\n              targetPath: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n          - task: CopyFiles@2\n            displayName: Flatten packages to PackageArtifacts\n            inputs:\n              SourceFolder: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n              Contents: '**/*.nupkg'\n              TargetFolder: '$(Build.ArtifactStagingDirectory)/PackageArtifacts'\n              flattenFolders: true\n\n        - task: PowerShell@2\n          displayName: Validate\n          inputs:\n            filePath: $(System.DefaultWorkingDirectory)/eng/common/post-build/nuget-validation.ps1\n            arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/\n\n    - job:\n      displayName: Signing Validation\n      condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true'))\n      pool:\n        # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n        ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n          name: AzurePipelines-EO\n          image: 1ESPT-Windows2025\n          demands: Cmd\n          os: windows\n        # If it's not devdiv, it's dnceng\n        ${{ else }}:\n          ${{ if eq(parameters.is1ESPipeline, true) }}:        \n            name: $(DncEngInternalBuildPool)\n            image: windows.vs2026.amd64\n            os: windows\n          ${{ else }}:\n            name: $(DncEngInternalBuildPool)\n            demands: ImageOverride -equals windows.vs2026preview.scout.amd64\n      steps:\n        - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n          parameters:\n            BARBuildId: ${{ parameters.BARBuildId }}\n            PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}\n            is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n        - ${{ if ne(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadBuildArtifacts@0\n            displayName: Download Package Artifacts\n            inputs:\n              buildType: specific\n              buildVersionToDownload: specific\n              project: $(AzDOProjectName)\n              pipeline: $(AzDOPipelineId)\n              buildId: $(AzDOBuildId)\n              artifactName: PackageArtifacts\n              checkDownloadedFiles: true\n        - ${{ if eq(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadPipelineArtifact@2\n            displayName: Download Pipeline Artifacts (V4)\n            inputs:\n              itemPattern: '*/packages/**/*.nupkg'\n              targetPath: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n          - task: CopyFiles@2\n            displayName: Flatten packages to PackageArtifacts\n            inputs:\n              SourceFolder: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n              Contents: '**/*.nupkg'\n              TargetFolder: '$(Build.ArtifactStagingDirectory)/PackageArtifacts'\n              flattenFolders: true\n\n        # This is necessary whenever we want to publish/restore to an AzDO private feed\n        # Since sdk-task.ps1 tries to restore packages we need to do this authentication here\n        # otherwise it'll complain about accessing a private feed.\n        - task: NuGetAuthenticate@1\n          displayName: 'Authenticate to AzDO Feeds'\n\n        # Signing validation will optionally work with the buildmanifest file which is downloaded from\n        # Azure DevOps above.\n        - task: PowerShell@2\n          displayName: Validate\n          inputs:\n            filePath: eng\\common\\sdk-task.ps1\n            arguments: -task SigningValidation -restore -msbuildEngine vs\n              /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'\n              /p:SignCheckExclusionsFile='$(System.DefaultWorkingDirectory)/eng/SignCheckExclusionsFile.txt'\n              ${{ parameters.signingValidationAdditionalParameters }}\n\n        - template: /eng/common/core-templates/steps/publish-logs.yml\n          parameters:\n            is1ESPipeline: ${{ parameters.is1ESPipeline }}\n            StageLabel: 'Validation'\n            JobLabel: 'Signing'\n            BinlogToolVersion: $(BinlogToolVersion)\n\n    - job:\n      displayName: SourceLink Validation\n      condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')\n      pool:\n        # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n        ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n          name: AzurePipelines-EO\n          image: 1ESPT-Windows2025\n          demands: Cmd\n          os: windows\n        # If it's not devdiv, it's dnceng\n        ${{ else }}:\n          ${{ if eq(parameters.is1ESPipeline, true) }}:          \n            name: $(DncEngInternalBuildPool)\n            image: windows.vs2026.amd64\n            os: windows\n          ${{ else }}:\n            name: $(DncEngInternalBuildPool)\n            demands: ImageOverride -equals windows.vs2026preview.scout.amd64\n      steps:\n        - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n          parameters:\n            BARBuildId: ${{ parameters.BARBuildId }}\n            PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}\n            is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n        - ${{ if ne(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadBuildArtifacts@0\n            displayName: Download Blob Artifacts\n            inputs:\n              buildType: specific\n              buildVersionToDownload: specific\n              project: $(AzDOProjectName)\n              pipeline: $(AzDOPipelineId)\n              buildId: $(AzDOBuildId)\n              artifactName: BlobArtifacts\n              checkDownloadedFiles: true\n        - ${{ if eq(parameters.publishingInfraVersion, 4) }}:\n          - task: DownloadPipelineArtifact@2\n            displayName: Download Pipeline Artifacts (V4)\n            inputs:\n              itemPattern: '*/assets/**'\n              targetPath: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n          - task: CopyFiles@2\n            displayName: Flatten assets to BlobArtifacts\n            inputs:\n              SourceFolder: '$(Build.ArtifactStagingDirectory)/PipelineArtifactsDownload'\n              Contents: '**/*'\n              TargetFolder: '$(Build.ArtifactStagingDirectory)/BlobArtifacts'\n              flattenFolders: true\n\n        - task: PowerShell@2\n          displayName: Validate\n          inputs:\n            filePath: $(System.DefaultWorkingDirectory)/eng/common/post-build/sourcelink-validation.ps1\n            arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ \n              -ExtractPath $(Agent.BuildDirectory)/Extract/ \n              -GHRepoName $(Build.Repository.Name) \n              -GHCommit $(Build.SourceVersion)\n              -SourcelinkCliVersion $(SourceLinkCLIVersion)\n          continueOnError: true\n\n- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}:\n  - stage: publish_using_darc\n    ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:\n      dependsOn: ${{ parameters.publishDependsOn }}\n    ${{ else }}:\n      dependsOn: ${{ parameters.validateDependsOn }}\n    displayName: Publish using Darc\n    variables:\n      - template: /eng/common/core-templates/post-build/common-variables.yml\n      - template: /eng/common/core-templates/variables/pool-providers.yml\n        parameters:\n          is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    jobs:\n    - job:\n      displayName: Publish Using Darc\n      timeoutInMinutes: 120\n      pool:\n        # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)\n        ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n          name: AzurePipelines-EO\n          image: 1ESPT-Windows2025\n          demands: Cmd\n          os: windows\n        # If it's not devdiv, it's dnceng\n        ${{ else }}:\n          ${{ if eq(parameters.is1ESPipeline, true) }}:          \n            name: NetCore1ESPool-Publishing-Internal\n            image: windows.vs2026.amd64\n            os: windows\n          ${{ else }}:\n            name: NetCore1ESPool-Publishing-Internal\n            demands: ImageOverride -equals windows.vs2026.amd64\n      steps:\n        - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n          parameters:\n            BARBuildId: ${{ parameters.BARBuildId }}\n            PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}\n            is1ESPipeline: ${{ parameters.is1ESPipeline }}\n\n        - task: NuGetAuthenticate@1\n\n        # Populate internal runtime variables.\n        - template: /eng/common/templates/steps/enable-internal-sources.yml\n          parameters:\n            legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw)\n\n        - template: /eng/common/templates/steps/enable-internal-runtimes.yml\n\n        # Darc is targeting 8.0, so make sure it's installed\n        - task: UseDotNet@2\n          inputs:\n            version: 8.0.x\n\n        - task: AzureCLI@2\n          displayName: Publish Using Darc\n          inputs:\n            azureSubscription: \"Darc: Maestro Production\"\n            scriptType: ps\n            scriptLocation: scriptPath\n            scriptPath: $(System.DefaultWorkingDirectory)/eng/common/post-build/publish-using-darc.ps1\n            arguments: >\n              -BuildId $(BARBuildId)\n              -PublishingInfraVersion 3\n              -AzdoToken '$(System.AccessToken)'\n              -WaitPublishingFinish true\n              -RequireDefaultChannels ${{ parameters.requireDefaultChannels }}\n              -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'\n              -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'\n              -SkipAssetsPublishing '${{ parameters.isAssetlessBuild }}'\n              -runtimeSourceFeed https://ci.dot.net/internal \n              -runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)'\n"
  },
  {
    "path": "eng/common/core-templates/post-build/setup-maestro-vars.yml",
    "content": "parameters:\n  BARBuildId: ''\n  PromoteToChannelIds: ''\n  is1ESPipeline: ''\n\nsteps:\n  - ${{ if eq(parameters.is1ESPipeline, '') }}:\n    - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error\n\n  - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:\n    - task: DownloadPipelineArtifact@2\n      displayName: Download Release Configs\n      inputs:\n        artifactName: ReleaseConfigs\n        targetPath: '$(Build.StagingDirectory)/ReleaseConfigs'\n\n  - task: AzureCLI@2\n    name: setReleaseVars\n    displayName: Set Release Configs Vars\n    inputs:\n      azureSubscription: \"Darc: Maestro Production\"\n      scriptType: pscore\n      scriptLocation: inlineScript\n      inlineScript: |\n        try {\n          if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {\n            $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt\n\n            $BarId = $Content | Select -Index 0\n            $Channels = $Content | Select -Index 1\n            $IsStableBuild = $Content | Select -Index 2\n\n            $AzureDevOpsProject = $Env:System_TeamProject\n            $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId\n            $AzureDevOpsBuildId = $Env:Build_BuildId\n          }\n          else {\n            . $(System.DefaultWorkingDirectory)\\eng\\common\\tools.ps1\n            $darc = Get-Darc\n            $buildInfo = & $darc get-build `\n              --id ${{ parameters.BARBuildId }} `\n              --extended `\n              --output-format json `\n              --ci `\n              | convertFrom-Json\n\n            $BarId = ${{ parameters.BARBuildId }}\n            $Channels = $Env:PromoteToMaestroChannels -split \",\"\n            $Channels = $Channels -join \"][\"\n            $Channels = \"[$Channels]\"\n\n            $IsStableBuild = $buildInfo.stable\n            $AzureDevOpsProject = $buildInfo.azureDevOpsProject\n            $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId\n            $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId\n          }\n\n          Write-Host \"##vso[task.setvariable variable=BARBuildId]$BarId\"\n          Write-Host \"##vso[task.setvariable variable=TargetChannels]$Channels\"\n          Write-Host \"##vso[task.setvariable variable=IsStableBuild]$IsStableBuild\"\n\n          Write-Host \"##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject\"\n          Write-Host \"##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId\"\n          Write-Host \"##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId\"\n        }\n        catch {\n          Write-Host $_\n          Write-Host $_.Exception\n          Write-Host $_.ScriptStackTrace\n          exit 1\n        }\n    env:\n      PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}\n"
  },
  {
    "path": "eng/common/core-templates/steps/cleanup-microbuild.yml",
    "content": "parameters:\n  # Enable cleanup tasks for MicroBuild\n  enableMicrobuild: false\n  # Enable cleanup tasks for MicroBuild on Mac and Linux\n  # Will be ignored if 'enableMicrobuild' is false or 'Agent.Os' is 'Windows_NT'\n  enableMicrobuildForMacAndLinux: false\n  continueOnError: false\n\nsteps:\n  - ${{ if eq(parameters.enableMicrobuild, 'true') }}:\n    - task: MicroBuildCleanup@1\n      displayName: Execute Microbuild cleanup tasks\n      condition: and(\n        always(),\n        or(\n          and(\n            eq(variables['Agent.Os'], 'Windows_NT'),\n            in(variables['_SignType'], 'real', 'test')\n          ),\n          and(\n            ${{ eq(parameters.enableMicrobuildForMacAndLinux, true) }},\n            ne(variables['Agent.Os'], 'Windows_NT'),\n            eq(variables['_SignType'], 'real')\n          )\n        ))\n      continueOnError: ${{ parameters.continueOnError }}\n      env:\n        TeamName: $(_TeamName)\n"
  },
  {
    "path": "eng/common/core-templates/steps/enable-internal-runtimes.yml",
    "content": "# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64'\n# variable with the base64-encoded SAS token, by default\n\nparameters:\n- name: federatedServiceConnection\n  type: string\n  default: 'dotnetbuilds-internal-read'\n- name: outputVariableName\n  type: string\n  default: 'dotnetbuilds-internal-container-read-token-base64'\n- name: expiryInHours\n  type: number\n  default: 1\n- name: base64Encode\n  type: boolean\n  default: true\n- name: is1ESPipeline\n  type: boolean\n  default: false\n\nsteps:\n- ${{ if ne(variables['System.TeamProject'], 'public') }}:\n  - template: /eng/common/core-templates/steps/get-delegation-sas.yml\n    parameters:\n      federatedServiceConnection: ${{ parameters.federatedServiceConnection }}\n      outputVariableName: ${{ parameters.outputVariableName }}\n      expiryInHours: ${{ parameters.expiryInHours }}\n      base64Encode: ${{ parameters.base64Encode }}\n      storageAccount: dotnetbuilds\n      container: internal\n      permissions: rl\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}"
  },
  {
    "path": "eng/common/core-templates/steps/enable-internal-sources.yml",
    "content": "parameters:\n# This is the Azure federated service connection that we log into to get an access token.\n- name: nugetFederatedServiceConnection\n  type: string\n  default: 'dnceng-artifacts-feeds-read'\n- name: is1ESPipeline\n  type: boolean\n  default: false\n# Legacy parameters to allow for PAT usage\n- name: legacyCredential\n  type: string\n  default: ''\n\nsteps:\n- ${{ if ne(variables['System.TeamProject'], 'public') }}:\n  - ${{ if ne(parameters.legacyCredential, '') }}:\n    - task: PowerShell@2\n      displayName: Setup Internal Feeds\n      inputs:\n        filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1\n        arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $Env:Token\n      env:\n        Token: ${{ parameters.legacyCredential }}\n  # If running on dnceng (internal project), just use the default behavior for NuGetAuthenticate.\n  # If running on DevDiv, NuGetAuthenticate is not really an option. It's scoped to a single feed, and we have many feeds that\n  # may be added. Instead, we'll use the traditional approach (add cred to nuget.config), but use an account token.\n  - ${{ else }}:\n    - ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n      - task: PowerShell@2\n        displayName: Setup Internal Feeds\n        inputs:\n          filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1\n          arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config\n    - ${{ else }}:\n      - template: /eng/common/templates/steps/get-federated-access-token.yml\n        parameters:\n          federatedServiceConnection: ${{ parameters.nugetFederatedServiceConnection }}\n          outputVariableName: 'dnceng-artifacts-feeds-read-access-token'\n      - task: PowerShell@2\n        displayName: Setup Internal Feeds\n        inputs:\n          filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1\n          arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $(dnceng-artifacts-feeds-read-access-token)\n  # This is required in certain scenarios to install the ADO credential provider.\n  # It installed by default in some msbuild invocations (e.g. VS msbuild), but needs to be installed for others\n  # (e.g. dotnet msbuild).\n  - task: NuGetAuthenticate@1\n"
  },
  {
    "path": "eng/common/core-templates/steps/generate-sbom.yml",
    "content": "parameters:\n  PackageVersion: unused\n  BuildDropPath: unused\n  PackageName: unused\n  ManifestDirPath: unused\n  IgnoreDirectories: unused\n  sbomContinueOnError: unused\n  is1ESPipeline: unused\n  publishArtifacts: unused\n\nsteps:\n- script: |\n    echo \"##vso[task.logissue type=warning]Including generate-sbom.yml is deprecated, SBOM generation is handled 1ES PT now. Remove this include.\"\n  displayName: Issue generate-sbom.yml deprecation warning\n"
  },
  {
    "path": "eng/common/core-templates/steps/get-delegation-sas.yml",
    "content": "parameters:\n- name: federatedServiceConnection\n  type: string\n- name: outputVariableName\n  type: string\n- name: expiryInHours\n  type: number\n  default: 1\n- name: base64Encode\n  type: boolean\n  default: false\n- name: storageAccount\n  type: string\n- name: container\n  type: string\n- name: permissions\n  type: string\n  default: 'rl'\n- name: is1ESPipeline\n  type: boolean\n  default: false\n\nsteps:\n- task: AzureCLI@2\n  displayName: 'Generate delegation SAS Token for ${{ parameters.storageAccount }}/${{ parameters.container }}'\n  inputs:\n    azureSubscription: ${{ parameters.federatedServiceConnection }}\n    scriptType: 'pscore'\n    scriptLocation: 'inlineScript'\n    inlineScript: |\n      # Calculate the expiration of the SAS token and convert to UTC\n      $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString(\"yyyy-MM-ddTHH:mm:ssZ\")\n\n      $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv\n\n      if ($LASTEXITCODE -ne 0) {\n        Write-Error \"Failed to generate SAS token.\"\n        exit 1\n      }\n\n      if ('${{ parameters.base64Encode }}' -eq 'true') {\n        $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas))\n      }\n\n      Write-Host \"Setting '${{ parameters.outputVariableName }}' with the access token value\"\n      Write-Host \"##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$sas\"\n"
  },
  {
    "path": "eng/common/core-templates/steps/get-federated-access-token.yml",
    "content": "parameters:\n- name: federatedServiceConnection\n  type: string\n- name: outputVariableName\n  type: string\n- name: is1ESPipeline\n  type: boolean\n- name: stepName\n  type: string\n  default: 'getFederatedAccessToken'\n- name: condition\n  type: string\n  default: ''\n# Resource to get a token for. Common values include:\n# - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps\n# - 'https://storage.azure.com/' for storage\n# Defaults to Azure DevOps\n- name: resource\n  type: string\n  default: '499b84ac-1321-427f-aa17-267ca6975798'\n- name: isStepOutputVariable\n  type: boolean\n  default: false\n\nsteps:\n- task: AzureCLI@2\n  displayName: 'Getting federated access token for feeds'\n  name: ${{ parameters.stepName }}\n  ${{ if ne(parameters.condition, '') }}:\n    condition: ${{ parameters.condition }}\n  inputs:\n    azureSubscription: ${{ parameters.federatedServiceConnection }}\n    scriptType: 'pscore'\n    scriptLocation: 'inlineScript'\n    inlineScript: |\n      $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv\n      if ($LASTEXITCODE -ne 0) {\n        Write-Error \"Failed to get access token for resource '${{ parameters.resource }}'\"\n        exit 1\n      }\n      Write-Host \"Setting '${{ parameters.outputVariableName }}' with the access token value\"\n      Write-Host \"##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken\""
  },
  {
    "path": "eng/common/core-templates/steps/install-microbuild.yml",
    "content": "parameters:\n  # Enable install tasks for MicroBuild\n  enableMicrobuild: false\n  # Enable install tasks for MicroBuild on Mac and Linux\n  # Will be ignored if 'enableMicrobuild' is false or 'Agent.Os' is 'Windows_NT'\n  enableMicrobuildForMacAndLinux: false\n  # Determines whether the ESRP service connection information should be passed to the signing plugin.\n  # This overlaps with _SignType to some degree. We only need the service connection for real signing.\n  # It's important that the service connection not be passed to the MicroBuildSigningPlugin task in this place.\n  # Doing so will cause the service connection to be authorized for the pipeline, which isn't allowed and won't work for non-prod.\n  # Unfortunately, _SignType can't be used to exclude the use of the service connection in non-real sign scenarios. The\n  # variable is not available in template expression. _SignType has a very large proliferation across .NET, so replacing it is tough.\n  microbuildUseESRP: true\n  # Microbuild installation directory\n  microBuildOutputFolder: $(Agent.TempDirectory)/MicroBuild\n\n  continueOnError: false\n\nsteps:\n  - ${{ if eq(parameters.enableMicrobuild, 'true') }}:\n    - ${{ if eq(parameters.enableMicrobuildForMacAndLinux, 'true') }}:\n      # Needed to download the MicroBuild plugin nupkgs on Mac and Linux when nuget.exe is unavailable\n      - task: UseDotNet@2\n        displayName: Install .NET 8.0 SDK for MicroBuild Plugin\n        inputs:\n          packageType: sdk\n          version: 8.0.x\n          installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet-microbuild\n        condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))\n\n      - script: |\n          set -euo pipefail\n\n          # UseDotNet@2 prepends the dotnet executable path to the PATH variable, so we can call dotnet directly\n          version=$(dotnet --version)\n          cat << 'EOF' > ${{ parameters.microBuildOutputFolder }}/global.json\n          {\n            \"sdk\": {\n              \"version\": \"$version\",\n              \"paths\": [\n                \"${{ parameters.microBuildOutputFolder }}/.dotnet-microbuild\"\n              ],\n              \"errorMessage\": \"The .NET SDK version $version is required to install the MicroBuild signing plugin.\"\n            }\n          }\n          EOF\n        displayName: 'Add global.json to MicroBuild Installation path'\n        workingDirectory: ${{ parameters.microBuildOutputFolder }}\n        condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))\n\n    - script: |\n        REM Check if ESRP is disabled while SignType is real\n        if /I \"${{ parameters.microbuildUseESRP }}\"==\"false\" if /I \"$(_SignType)\"==\"real\" (\n          echo Error: ESRP must be enabled when SignType is real.\n          exit /b 1\n        )\n      displayName: 'Validate ESRP usage (Windows)'\n      condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'))\n    - script: |\n        # Check if ESRP is disabled while SignType is real\n        if [ \"${{ parameters.microbuildUseESRP }}\" = \"false\" ] && [ \"$(_SignType)\" = \"real\" ]; then\n          echo \"Error: ESRP must be enabled when SignType is real.\"\n          exit 1\n        fi\n      displayName: 'Validate ESRP usage (Non-Windows)'\n      condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))\n\n    # Two different MB install steps. This is due to not being able to use the agent OS during\n    # YAML expansion, and Windows vs. Linux/Mac uses different service connections. However,\n    # we can avoid including the MB install step if not enabled at all. This avoids a bunch of\n    # extra pipeline authorizations, since most pipelines do not sign on non-Windows.\n    - task: MicroBuildSigningPlugin@4\n      displayName: Install MicroBuild plugin (Windows)\n      inputs:\n        signType: $(_SignType)\n        zipSources: false\n        feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json\n        ${{ if eq(parameters.microbuildUseESRP, true) }}:\n          ConnectedServiceName: 'MicroBuild Signing Task (DevDiv)'\n          ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n            ConnectedPMEServiceName: 6cc74545-d7b9-4050-9dfa-ebefcc8961ea\n          ${{ else }}:\n            ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca\n      env:\n        TeamName: $(_TeamName)\n        MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }}\n        SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n      continueOnError: ${{ parameters.continueOnError }}\n      condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'), in(variables['_SignType'], 'real', 'test'))\n\n    - ${{ if eq(parameters.enableMicrobuildForMacAndLinux, true) }}:\n      - task: MicroBuildSigningPlugin@4\n        displayName: Install MicroBuild plugin (non-Windows)\n        inputs:\n          signType: $(_SignType)\n          zipSources: false\n          feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json\n          workingDirectory: ${{ parameters.microBuildOutputFolder }}\n          ${{ if eq(parameters.microbuildUseESRP, true) }}:\n            ConnectedServiceName: 'MicroBuild Signing Task (DevDiv)'\n            ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:\n              ConnectedPMEServiceName: beb8cb23-b303-4c95-ab26-9e44bc958d39\n            ${{ else }}:\n              ConnectedPMEServiceName: c24de2a5-cc7a-493d-95e4-8e5ff5cad2bc\n        env:\n          TeamName: $(_TeamName)\n          MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }}\n          SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n        continueOnError: ${{ parameters.continueOnError }}\n        condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'),  eq(variables['_SignType'], 'real'))\n"
  },
  {
    "path": "eng/common/core-templates/steps/publish-build-artifacts.yml",
    "content": "parameters:\n- name: is1ESPipeline\n  type: boolean\n  default: false\n- name: args\n  type: object\n  default: {}\nsteps:\n- ${{ if ne(parameters.is1ESPipeline, true) }}:\n  - template: /eng/common/templates/steps/publish-build-artifacts.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      ${{ each parameter in parameters.args }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n- ${{ else }}:\n  - template: /eng/common/templates-official/steps/publish-build-artifacts.yml\n    parameters:\n      is1ESPipeline: ${{ parameters.is1ESPipeline }}\n      ${{ each parameter in parameters.args }}:\n        ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/core-templates/steps/publish-logs.yml",
    "content": "parameters:\n  StageLabel: ''\n  JobLabel: ''\n  CustomSensitiveDataList: ''\n  # A default - in case value from eng/common/core-templates/post-build/common-variables.yml is not passed\n  BinlogToolVersion: '1.0.11'\n  is1ESPipeline: false\n\nsteps:\n- task: Powershell@2\n  displayName: Prepare Binlogs to Upload\n  inputs:\n    targetType: inline\n    script: |\n      New-Item -ItemType Directory $(System.DefaultWorkingDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/\n      Move-Item -Path $(System.DefaultWorkingDirectory)/artifacts/log/Debug/* $(System.DefaultWorkingDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/\n  continueOnError: true\n  condition: always()\n    \n- task: PowerShell@2\n  displayName: Redact Logs\n  inputs:\n    filePath: $(System.DefaultWorkingDirectory)/eng/common/post-build/redact-logs.ps1\n    # For now this needs to have explicit list of all sensitive data. Taken from eng/publishing/v3/publish.yml\n    # Sensitive data can as well be added to $(System.DefaultWorkingDirectory)/eng/BinlogSecretsRedactionFile.txt'\n    #  If the file exists - sensitive data for redaction will be sourced from it\n    #  (single entry per line, lines starting with '# ' are considered comments and skipped)\n    arguments: -InputPath '$(System.DefaultWorkingDirectory)/PostBuildLogs' \n      -BinlogToolVersion '${{parameters.BinlogToolVersion}}'\n      -TokensFilePath '$(System.DefaultWorkingDirectory)/eng/BinlogSecretsRedactionFile.txt'\n      -runtimeSourceFeed https://ci.dot.net/internal \n      -runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)'\n      '$(publishing-dnceng-devdiv-code-r-build-re)'\n      '$(dn-bot-all-orgs-artifact-feeds-rw)'\n      '$(akams-client-id)'\n      '$(microsoft-symbol-server-pat)'\n      '$(symweb-symbol-server-pat)'\n      '$(dnceng-symbol-server-pat)'\n      '$(dn-bot-all-orgs-build-rw-code-rw)'\n      '$(System.AccessToken)'\n      ${{parameters.CustomSensitiveDataList}}\n  continueOnError: true\n  condition: always()\n\n- task: CopyFiles@2\n  displayName: Gather post build logs\n  inputs:\n    SourceFolder: '$(System.DefaultWorkingDirectory)/PostBuildLogs'\n    Contents: '**'\n    TargetFolder: '$(Build.ArtifactStagingDirectory)/PostBuildLogs'\n  condition: always()\n\n- template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n  parameters:\n    is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    args:\n      displayName: Publish Logs\n      targetPath: '$(Build.ArtifactStagingDirectory)/PostBuildLogs'\n      artifactName: PostBuildLogs_${{ parameters.StageLabel }}_${{ parameters.JobLabel }}_Attempt$(System.JobAttempt)\n      continueOnError: true\n      condition: always()\n      retryCountOnTaskFailure: 10 # for any files being locked\n      isProduction: false # logs are non-production artifacts\n"
  },
  {
    "path": "eng/common/core-templates/steps/publish-pipeline-artifacts.yml",
    "content": "parameters:\n- name: is1ESPipeline\n  type: boolean\n  default: false\n\n- name: args\n  type: object\n  default: {}  \n\nsteps:\n- ${{ if ne(parameters.is1ESPipeline, true) }}:\n  - template: /eng/common/templates/steps/publish-pipeline-artifacts.yml\n    parameters:\n      ${{ each parameter in parameters }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n- ${{ else }}:\n  - template: /eng/common/templates-official/steps/publish-pipeline-artifacts.yml\n    parameters:\n      ${{ each parameter in parameters }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/core-templates/steps/retain-build.yml",
    "content": "parameters:\n  # Optional azure devops PAT with build execute permissions for the build's organization,\n  # only needed if the build that should be retained ran on a different organization than \n  # the pipeline where this template is executing from\n  Token: ''\n  # Optional BuildId to retain, defaults to the current running build\n  BuildId: ''\n  # Azure devops Organization URI for the build in the https://dev.azure.com/<organization> format.\n  # Defaults to the organization the current pipeline is running on\n  AzdoOrgUri: '$(System.CollectionUri)'\n  # Azure devops project for the build. Defaults to the project the current pipeline is running on\n  AzdoProject: '$(System.TeamProject)'\n\nsteps:\n  - task: powershell@2\n    inputs:\n      targetType: 'filePath'\n      filePath: eng/common/retain-build.ps1\n      pwsh: true\n      arguments: >\n        -AzdoOrgUri: ${{parameters.AzdoOrgUri}}\n        -AzdoProject ${{parameters.AzdoProject}}\n        -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }}\n        -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}}\n    displayName: Enable permanent build retention\n    env:\n      SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n      BUILD_ID: $(Build.BuildId)"
  },
  {
    "path": "eng/common/core-templates/steps/send-to-helix.yml",
    "content": "# Please remember to update the documentation if you make changes to these parameters!\nparameters:\n  HelixSource: 'pr/default'              # required -- sources must start with pr/, official/, prodcon/, or agent/\n  HelixType: 'tests/default/'            # required -- Helix telemetry which identifies what type of data this is; should include \"test\" for clarity and must end in '/'\n  HelixBuild: $(Build.BuildNumber)       # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number\n  HelixTargetQueues: ''                  # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues\n  HelixAccessToken: ''                   # required -- access token to make Helix API requests; should be provided by the appropriate variable group\n  HelixProjectPath: 'eng/common/helixpublish.proj'  # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY\n  HelixProjectArguments: ''              # optional -- arguments passed to the build command\n  HelixConfiguration: ''                 # optional -- additional property attached to a job\n  HelixPreCommands: ''                   # optional -- commands to run before Helix work item execution\n  HelixPostCommands: ''                  # optional -- commands to run after Helix work item execution\n  WorkItemDirectory: ''                  # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects\n  WorkItemCommand: ''                    # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects\n  WorkItemTimeout: ''                    # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects\n  CorrelationPayloadDirectory: ''        # optional -- a directory to zip up and send to Helix as a correlation payload\n  XUnitProjects: ''                      # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true\n  XUnitWorkItemTimeout: ''               # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects\n  XUnitPublishTargetFramework: ''        # optional -- framework to use to publish your xUnit projects\n  XUnitRuntimeTargetFramework: ''        # optional -- framework to use for the xUnit console runner\n  XUnitRunnerVersion: ''                 # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects\n  IncludeDotNetCli: false                # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion\n  DotNetCliPackageType: ''               # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json\n  DotNetCliVersion: ''                   # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json\n  WaitForWorkItemCompletion: true        # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is \"fire and forget.\"\n  IsExternal: false                      # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set\n  HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net )\n  Creator: ''                            # optional -- if the build is external, use this to specify who is sending the job\n  DisplayNamePrefix: 'Run Tests'         # optional -- rename the beginning of the displayName of the steps in AzDO \n  condition: succeeded()                 # optional -- condition for step to execute; defaults to succeeded()\n  continueOnError: false                 # optional -- determines whether to continue the build if the step errors; defaults to false\n\nsteps:\n  - powershell: 'powershell \"$env:BUILD_SOURCESDIRECTORY\\eng\\common\\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\\artifacts\\log\\$env:BuildConfig\\SendToHelix.binlog\"'\n    displayName: ${{ parameters.DisplayNamePrefix }} (Windows)\n    env:\n      BuildConfig: $(_BuildConfig)\n      HelixSource: ${{ parameters.HelixSource }}\n      HelixType: ${{ parameters.HelixType }}\n      HelixBuild: ${{ parameters.HelixBuild }}\n      HelixConfiguration:  ${{ parameters.HelixConfiguration }}\n      HelixTargetQueues: ${{ parameters.HelixTargetQueues }}\n      HelixAccessToken: ${{ parameters.HelixAccessToken }}\n      HelixPreCommands: ${{ parameters.HelixPreCommands }}\n      HelixPostCommands: ${{ parameters.HelixPostCommands }}\n      WorkItemDirectory: ${{ parameters.WorkItemDirectory }}\n      WorkItemCommand: ${{ parameters.WorkItemCommand }}\n      WorkItemTimeout: ${{ parameters.WorkItemTimeout }}\n      CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}\n      XUnitProjects: ${{ parameters.XUnitProjects }}\n      XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}\n      XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}\n      XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}\n      XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}\n      IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}\n      DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}\n      DotNetCliVersion: ${{ parameters.DotNetCliVersion }}\n      WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}\n      HelixBaseUri: ${{ parameters.HelixBaseUri }}\n      Creator: ${{ parameters.Creator }}\n      SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n    condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))\n    continueOnError: ${{ parameters.continueOnError }}\n  - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog\n    displayName: ${{ parameters.DisplayNamePrefix }} (Unix)\n    env:\n      BuildConfig: $(_BuildConfig)\n      HelixSource: ${{ parameters.HelixSource }}\n      HelixType: ${{ parameters.HelixType }}\n      HelixBuild: ${{ parameters.HelixBuild }}\n      HelixConfiguration:  ${{ parameters.HelixConfiguration }}\n      HelixTargetQueues: ${{ parameters.HelixTargetQueues }}\n      HelixAccessToken: ${{ parameters.HelixAccessToken }}\n      HelixPreCommands: ${{ parameters.HelixPreCommands }}\n      HelixPostCommands: ${{ parameters.HelixPostCommands }}\n      WorkItemDirectory: ${{ parameters.WorkItemDirectory }}\n      WorkItemCommand: ${{ parameters.WorkItemCommand }}\n      WorkItemTimeout: ${{ parameters.WorkItemTimeout }}\n      CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}\n      XUnitProjects: ${{ parameters.XUnitProjects }}\n      XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}\n      XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}\n      XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}\n      XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}\n      IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}\n      DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}\n      DotNetCliVersion: ${{ parameters.DotNetCliVersion }}\n      WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}\n      HelixBaseUri: ${{ parameters.HelixBaseUri }}\n      Creator: ${{ parameters.Creator }}\n      SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n    condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))\n    continueOnError: ${{ parameters.continueOnError }}\n"
  },
  {
    "path": "eng/common/core-templates/steps/source-build.yml",
    "content": "parameters:\n  # This template adds arcade-powered source-build to CI.\n\n  # This is a 'steps' template, and is intended for advanced scenarios where the existing build\n  # infra has a careful build methodology that must be followed. For example, a repo\n  # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline\n  # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to\n  # GitHub. Using this steps template leaves room for that infra to be included.\n\n  # Defines the platform on which to run the steps. See 'eng/common/core-templates/job/source-build.yml'\n  # for details. The entire object is described in the 'job' template for simplicity, even though\n  # the usage of the properties on this object is split between the 'job' and 'steps' templates.\n  platform: {}\n  is1ESPipeline: false\n\nsteps:\n# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.)\n- script: |\n    set -x\n    df -h\n\n    # If building on the internal project, the internal storage variable may be available (usually only if needed)\n    # In that case, add variables to allow the download of internal runtimes if the specified versions are not found\n    # in the default public locations.\n    internalRuntimeDownloadArgs=\n    if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then\n      internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://ci.dot.net/internal --runtimesourcefeedkey '$(dotnetbuilds-internal-container-read-token-base64)''\n    fi\n\n    buildConfig=Release\n    # Check if AzDO substitutes in a build config from a variable, and use it if so.\n    if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then\n      buildConfig='$(_BuildConfig)'\n    fi\n\n    targetRidArgs=\n    if [ '${{ parameters.platform.targetRID }}' != '' ]; then\n      targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}'\n    fi\n\n    portableBuildArgs=\n    if [ '${{ parameters.platform.portableBuild }}' != '' ]; then\n      portableBuildArgs='/p:PortableBuild=${{ parameters.platform.portableBuild }}'\n    fi\n\n    ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \\\n      --configuration $buildConfig \\\n      --restore --build --pack -bl \\\n      --source-build \\\n      ${{ parameters.platform.buildArguments }} \\\n      $internalRuntimeDownloadArgs \\\n      $targetRidArgs \\\n      $portableBuildArgs \\\n  displayName: Build\n\n- template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n  parameters:\n    is1ESPipeline: ${{ parameters.is1ESPipeline }}\n    args:\n      displayName: Publish BuildLogs\n      targetPath: artifacts/log/${{ coalesce(variables._BuildConfig, 'Release') }}\n      artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)\n      continueOnError: true\n      condition: succeededOrFailed()\n      isProduction: false # logs are non-production artifacts\n"
  },
  {
    "path": "eng/common/core-templates/steps/source-index-stage1-publish.yml",
    "content": "parameters:\n  sourceIndexUploadPackageVersion: 2.0.0-20250818.1\n  sourceIndexProcessBinlogPackageVersion: 1.0.1-20250818.1\n  sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json\n  binlogPath: artifacts/log/Debug/Build.binlog\n\nsteps:\n- task: UseDotNet@2\n  displayName: \"Source Index: Use .NET 9 SDK\"\n  inputs:\n    packageType: sdk\n    version: 9.0.x\n    installationPath: $(Agent.TempDirectory)/dotnet\n    workingDirectory: $(Agent.TempDirectory)\n\n- script: |\n    $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version ${{parameters.sourceIndexProcessBinlogPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools\n    $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version ${{parameters.sourceIndexUploadPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools\n  displayName: \"Source Index: Download netsourceindex Tools\"\n  # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.\n  workingDirectory: $(Agent.TempDirectory)\n\n- script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i ${{parameters.BinlogPath}} -r $(System.DefaultWorkingDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output\n  displayName: \"Source Index: Process Binlog into indexable sln\"\n\n- ${{ if and(ne(parameters.runAsPublic, 'true'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:\n  - task: AzureCLI@2\n    displayName: \"Source Index: Upload Source Index stage1 artifacts to Azure\"\n    inputs:\n      azureSubscription: 'SourceDotNet Stage1 Publish'\n      addSpnToEnvironment: true\n      scriptType: 'ps'\n      scriptLocation: 'inlineScript'\n      inlineScript: |\n        $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1\n"
  },
  {
    "path": "eng/common/core-templates/variables/pool-providers.yml",
    "content": "parameters:\n  is1ESPipeline: false\n\nvariables:\n  - ${{ if eq(parameters.is1ESPipeline, 'true') }}:\n    - template: /eng/common/templates-official/variables/pool-providers.yml\n  - ${{ else }}:\n    - template: /eng/common/templates/variables/pool-providers.yml"
  },
  {
    "path": "eng/common/cross/arm/tizen/tizen.patch",
    "content": "diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so\n--- a/usr/lib/libc.so\t2016-12-30 23:00:08.284951863 +0900\n+++ b/usr/lib/libc.so\t2016-12-30 23:00:32.140951815 +0900\n@@ -2,4 +2,4 @@\n    Use the shared library, but some functions are only in\n    the static library, so try that secondarily.  */\n OUTPUT_FORMAT(elf32-littlearm)\n-GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux-armhf.so.3 ) )\n+GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-armhf.so.3 ) )\n"
  },
  {
    "path": "eng/common/cross/arm64/tizen/tizen.patch",
    "content": "diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so\n--- a/usr/lib64/libc.so\t2016-12-30 23:00:08.284951863 +0900\n+++ b/usr/lib64/libc.so\t2016-12-30 23:00:32.140951815 +0900\n@@ -2,4 +2,4 @@\n    Use the shared library, but some functions are only in\n    the static library, so try that secondarily.  */\n OUTPUT_FORMAT(elf64-littleaarch64)\n-GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /lib64/ld-linux-aarch64.so.1 ) )\n+GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-aarch64.so.1 ) )\n"
  },
  {
    "path": "eng/common/cross/armel/tizen/tizen.patch",
    "content": "diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so\n--- a/usr/lib/libc.so\t2016-12-30 23:00:08.284951863 +0900\n+++ b/usr/lib/libc.so\t2016-12-30 23:00:32.140951815 +0900\n@@ -2,4 +2,4 @@\n    Use the shared library, but some functions are only in\n    the static library, so try that secondarily.  */\n OUTPUT_FORMAT(elf32-littlearm)\n-GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux.so.3 ) )\n+GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux.so.3 ) )\n"
  },
  {
    "path": "eng/common/cross/build-android-rootfs.sh",
    "content": "#!/usr/bin/env bash\nset -e\n__NDK_Version=r21\n\nusage()\n{\n    echo \"Creates a toolchain and sysroot used for cross-compiling for Android.\"\n    echo\n    echo \"Usage: $0 [BuildArch] [ApiLevel] [--ndk NDKVersion]\"\n    echo\n    echo \"BuildArch is the target architecture of Android. Currently only arm64 is supported.\"\n    echo \"ApiLevel is the target Android API level. API levels usually match to Android releases. See https://source.android.com/source/build-numbers.html\"\n    echo \"NDKVersion is the version of Android NDK. The default is r21. See https://developer.android.com/ndk/downloads/revision_history\"\n    echo\n    echo \"By default, the toolchain and sysroot will be generated in cross/android-rootfs/toolchain/[BuildArch]. You can change this behavior\"\n    echo \"by setting the TOOLCHAIN_DIR environment variable\"\n    echo\n    echo \"By default, the NDK will be downloaded into the cross/android-rootfs/android-ndk-$__NDK_Version directory. If you already have an NDK installation,\"\n    echo \"you can set the NDK_DIR environment variable to have this script use that installation of the NDK.\"\n    echo \"By default, this script will generate a file, android_platform, in the root of the ROOTFS_DIR directory that contains the RID for the supported and tested Android build: android.28-arm64. This file is to replace '/etc/os-release', which is not available for Android.\"\n    exit 1\n}\n\n__ApiLevel=28 # The minimum platform for arm64 is API level 21 but the minimum version that support glob(3) is 28. See $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/glob.h\n__BuildArch=arm64\n__AndroidArch=aarch64\n__AndroidToolchain=aarch64-linux-android\n\nwhile :; do\n    if [[ \"$#\" -le 0 ]]; then\n        break\n    fi\n\n    i=$1\n\n    lowerI=\"$(echo $i | tr \"[:upper:]\" \"[:lower:]\")\"\n    case $lowerI in\n        -?|-h|--help)\n            usage\n            exit 1\n            ;;\n        arm64)\n            __BuildArch=arm64\n            __AndroidArch=aarch64\n            __AndroidToolchain=aarch64-linux-android\n            ;;\n        arm)\n            __BuildArch=arm\n            __AndroidArch=arm\n            __AndroidToolchain=arm-linux-androideabi\n            ;;\n        --ndk)\n            shift\n            __NDK_Version=$1\n            ;;\n        *[0-9])\n            __ApiLevel=$i\n            ;;\n        *)\n            __UnprocessedBuildArgs=\"$__UnprocessedBuildArgs $i\"\n            ;;\n    esac\n    shift\ndone\n\nif [[ \"$__NDK_Version\" == \"r21\" ]] || [[ \"$__NDK_Version\" == \"r22\" ]]; then\n    __NDK_File_Arch_Spec=-x86_64\n    __SysRoot=sysroot\nelse\n    __NDK_File_Arch_Spec=\n    __SysRoot=toolchains/llvm/prebuilt/linux-x86_64/sysroot\nfi\n\n# Obtain the location of the bash script to figure out where the root of the repo is.\n__ScriptBaseDir=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\n__CrossDir=\"$__ScriptBaseDir/../../../.tools/android-rootfs\"\n\nif [[ ! -f \"$__CrossDir\" ]]; then\n    mkdir -p \"$__CrossDir\"\nfi\n\n# Resolve absolute path to avoid `../` in build logs\n__CrossDir=\"$( cd \"$__CrossDir\" && pwd )\"\n\n__NDK_Dir=\"$__CrossDir/android-ndk-$__NDK_Version\"\n__lldb_Dir=\"$__CrossDir/lldb\"\n__ToolchainDir=\"$__CrossDir/android-ndk-$__NDK_Version\"\n\nif [[ -n \"$TOOLCHAIN_DIR\" ]]; then\n    __ToolchainDir=$TOOLCHAIN_DIR\nfi\n\nif [[ -n \"$NDK_DIR\" ]]; then\n    __NDK_Dir=$NDK_DIR\nfi\n\necho \"Target API level: $__ApiLevel\"\necho \"Target architecture: $__BuildArch\"\necho \"NDK version: $__NDK_Version\"\necho \"NDK location: $__NDK_Dir\"\necho \"Target Toolchain location: $__ToolchainDir\"\n\n# Download the NDK if required\nif [ ! -d $__NDK_Dir ]; then\n    echo Downloading the NDK into $__NDK_Dir\n    mkdir -p $__NDK_Dir\n    wget -q --progress=bar:force:noscroll --show-progress https://dl.google.com/android/repository/android-ndk-$__NDK_Version-linux$__NDK_File_Arch_Spec.zip -O $__CrossDir/android-ndk-$__NDK_Version-linux.zip\n    unzip -q $__CrossDir/android-ndk-$__NDK_Version-linux.zip -d $__CrossDir\nfi\n\nif [ ! -d $__lldb_Dir ]; then\n    mkdir -p $__lldb_Dir\n    echo Downloading LLDB into $__lldb_Dir\n    wget -q --progress=bar:force:noscroll --show-progress https://dl.google.com/android/repository/lldb-2.3.3614996-linux-x86_64.zip -O $__CrossDir/lldb-2.3.3614996-linux-x86_64.zip\n    unzip -q $__CrossDir/lldb-2.3.3614996-linux-x86_64.zip -d $__lldb_Dir\nfi\n\necho \"Download dependencies...\"\n__TmpDir=$__CrossDir/tmp/$__BuildArch/\nmkdir -p \"$__TmpDir\"\n\n# combined dependencies for coreclr, installer and libraries\n__AndroidPackages=\"libicu\"\n__AndroidPackages+=\" libandroid-glob\"\n__AndroidPackages+=\" liblzma\"\n__AndroidPackages+=\" krb5\"\n__AndroidPackages+=\" openssl\"\n\nfor path in $(wget -qO- https://packages.termux.dev/termux-main-21/dists/stable/main/binary-$__AndroidArch/Packages |\\\n    grep -A15 \"Package: \\(${__AndroidPackages// /\\\\|}\\)\" | grep -v \"static\\|tool\" | grep Filename); do\n\n    if [[ \"$path\" != \"Filename:\" ]]; then\n        echo \"Working on: $path\"\n        wget -qO- https://packages.termux.dev/termux-main-21/$path | dpkg -x - \"$__TmpDir\"\n    fi\ndone\n\ncp -R \"$__TmpDir/data/data/com.termux/files/usr/\"* \"$__ToolchainDir/$__SysRoot/usr/\"\n\n# Generate platform file for build.sh script to assign to __DistroRid\necho \"Generating platform file...\"\necho \"RID=android.${__ApiLevel}-${__BuildArch}\" > $__ToolchainDir/$__SysRoot/android_platform\n\necho \"Now to build coreclr, libraries and host; run:\"\necho ROOTFS_DIR=$(realpath $__ToolchainDir/$__SysRoot) ./build.sh clr+libs+host --cross --arch $__BuildArch\n"
  },
  {
    "path": "eng/common/cross/build-rootfs.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\nusage()\n{\n    echo \"Usage: $0 [BuildArch] [CodeName] [lldbx.y] [llvmx[.y]] [--skipunmount] --rootfsdir <directory>]\"\n    echo \"BuildArch can be: arm(default), arm64, armel, armv6, loongarch64, ppc64le, riscv64, s390x, x64, x86\"\n    echo \"CodeName - optional, Code name for Linux, can be: xenial(default), zesty, bionic, alpine\"\n    echo \"                               for alpine can be specified with version: alpineX.YY or alpineedge\"\n    echo \"                               for FreeBSD can be: freebsd13, freebsd14\"\n    echo \"                               for illumos can be: illumos\"\n    echo \"                               for Haiku can be: haiku.\"\n    echo \"lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FreeBSD\"\n    echo \"llvmx[.y] - optional, LLVM version for LLVM related packages.\"\n    echo \"--skipunmount - optional, will skip the unmount of rootfs folder.\"\n    echo \"--skipsigcheck - optional, will skip package signature checks (allowing untrusted packages).\"\n    echo \"--skipemulation - optional, will skip qemu and debootstrap requirement when building environment for debian based systems.\"\n    echo \"--use-mirror - optional, use mirror URL to fetch resources, when available.\"\n    echo \"--jobs N - optional, restrict to N jobs.\"\n    exit 1\n}\n\n__CodeName=xenial\n__CrossDir=$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\n__BuildArch=arm\n__AlpineArch=armv7\n__FreeBSDArch=arm\n__FreeBSDMachineArch=armv7\n__IllumosArch=arm7\n__HaikuArch=arm\n__QEMUArch=arm\n__UbuntuArch=armhf\n__UbuntuRepo=\n__UbuntuSuites=\"updates security backports\"\n__LLDB_Package=\"liblldb-3.9-dev\"\n__SkipUnmount=0\n\n# base development support\n__UbuntuPackages=\"build-essential\"\n\n__AlpinePackages=\"alpine-base\"\n__AlpinePackages+=\" build-base\"\n__AlpinePackages+=\" linux-headers\"\n__AlpinePackages+=\" lldb-dev\"\n__AlpinePackages+=\" python3\"\n__AlpinePackages+=\" libedit\"\n\n# symlinks fixer\n__UbuntuPackages+=\" symlinks\"\n\n# runtime dependencies\n__UbuntuPackages+=\" libicu-dev\"\n__UbuntuPackages+=\" liblttng-ust-dev\"\n__UbuntuPackages+=\" libunwind8-dev\"\n\n__AlpinePackages+=\" gettext-dev\"\n__AlpinePackages+=\" icu-dev\"\n__AlpinePackages+=\" libunwind-dev\"\n__AlpinePackages+=\" lttng-ust-dev\"\n__AlpinePackages+=\" compiler-rt\"\n\n# runtime libraries' dependencies\n__UbuntuPackages+=\" libcurl4-openssl-dev\"\n__UbuntuPackages+=\" libkrb5-dev\"\n__UbuntuPackages+=\" libssl-dev\"\n__UbuntuPackages+=\" zlib1g-dev\"\n__UbuntuPackages+=\" libbrotli-dev\"\n\n__AlpinePackages+=\" curl-dev\"\n__AlpinePackages+=\" krb5-dev\"\n__AlpinePackages+=\" openssl-dev\"\n__AlpinePackages+=\" zlib-dev\"\n\n__FreeBSDBase=\"13.4-RELEASE\"\n__FreeBSDPkg=\"1.21.3\"\n__FreeBSDABI=\"13\"\n__FreeBSDPackages=\"libunwind\"\n__FreeBSDPackages+=\" icu\"\n__FreeBSDPackages+=\" libinotify\"\n__FreeBSDPackages+=\" openssl\"\n__FreeBSDPackages+=\" krb5\"\n__FreeBSDPackages+=\" terminfo-db\"\n\n__IllumosPackages=\"icu\"\n__IllumosPackages+=\" mit-krb5\"\n__IllumosPackages+=\" openssl\"\n__IllumosPackages+=\" zlib\"\n\n__HaikuPackages=\"gcc_syslibs\"\n__HaikuPackages+=\" gcc_syslibs_devel\"\n__HaikuPackages+=\" gmp\"\n__HaikuPackages+=\" gmp_devel\"\n__HaikuPackages+=\" icu[0-9]+\"\n__HaikuPackages+=\" icu[0-9]*_devel\"\n__HaikuPackages+=\" krb5\"\n__HaikuPackages+=\" krb5_devel\"\n__HaikuPackages+=\" libiconv\"\n__HaikuPackages+=\" libiconv_devel\"\n__HaikuPackages+=\" llvm[0-9]*_libunwind\"\n__HaikuPackages+=\" llvm[0-9]*_libunwind_devel\"\n__HaikuPackages+=\" mpfr\"\n__HaikuPackages+=\" mpfr_devel\"\n__HaikuPackages+=\" openssl3\"\n__HaikuPackages+=\" openssl3_devel\"\n__HaikuPackages+=\" zlib\"\n__HaikuPackages+=\" zlib_devel\"\n\n# ML.NET dependencies\n__UbuntuPackages+=\" libomp5\"\n__UbuntuPackages+=\" libomp-dev\"\n\n# Taken from https://github.com/alpinelinux/alpine-chroot-install/blob/6d08f12a8a70dd9b9dc7d997c88aa7789cc03c42/alpine-chroot-install#L85-L133\n__AlpineKeys='\n4a6a0840:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1yHJxQgsHQREclQu4Ohe\\nqxTxd1tHcNnvnQTu/UrTky8wWvgXT+jpveroeWWnzmsYlDI93eLI2ORakxb3gA2O\\nQ0Ry4ws8vhaxLQGC74uQR5+/yYrLuTKydFzuPaS1dK19qJPXB8GMdmFOijnXX4SA\\njixuHLe1WW7kZVtjL7nufvpXkWBGjsfrvskdNA/5MfxAeBbqPgaq0QMEfxMAn6/R\\nL5kNepi/Vr4S39Xvf2DzWkTLEK8pcnjNkt9/aafhWqFVW7m3HCAII6h/qlQNQKSo\\nGuH34Q8GsFG30izUENV9avY7hSLq7nggsvknlNBZtFUcmGoQrtx3FmyYsIC8/R+B\\nywIDAQAB\n5243ef4b:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvNijDxJ8kloskKQpJdx+\\nmTMVFFUGDoDCbulnhZMJoKNkSuZOzBoFC94omYPtxnIcBdWBGnrm6ncbKRlR+6oy\\nDO0W7c44uHKCFGFqBhDasdI4RCYP+fcIX/lyMh6MLbOxqS22TwSLhCVjTyJeeH7K\\naA7vqk+QSsF4TGbYzQDDpg7+6aAcNzg6InNePaywA6hbT0JXbxnDWsB+2/LLSF2G\\nmnhJlJrWB1WGjkz23ONIWk85W4S0XB/ewDefd4Ly/zyIciastA7Zqnh7p3Ody6Q0\\nsS2MJzo7p3os1smGjUF158s6m/JbVh4DN6YIsxwl2OjDOz9R0OycfJSDaBVIGZzg\\ncQIDAQAB\n524d27bb:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr8s1q88XpuJWLCZALdKj\\nlN8wg2ePB2T9aIcaxryYE/Jkmtu+ZQ5zKq6BT3y/udt5jAsMrhHTwroOjIsF9DeG\\ne8Y3vjz+Hh4L8a7hZDaw8jy3CPag47L7nsZFwQOIo2Cl1SnzUc6/owoyjRU7ab0p\\niWG5HK8IfiybRbZxnEbNAfT4R53hyI6z5FhyXGS2Ld8zCoU/R4E1P0CUuXKEN4p0\\n64dyeUoOLXEWHjgKiU1mElIQj3k/IF02W89gDj285YgwqA49deLUM7QOd53QLnx+\\nxrIrPv3A+eyXMFgexNwCKQU9ZdmWa00MjjHlegSGK8Y2NPnRoXhzqSP9T9i2HiXL\\nVQIDAQAB\n5261cecb:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwlzMkl7b5PBdfMzGdCT0\\ncGloRr5xGgVmsdq5EtJvFkFAiN8Ac9MCFy/vAFmS8/7ZaGOXoCDWbYVLTLOO2qtX\\nyHRl+7fJVh2N6qrDDFPmdgCi8NaE+3rITWXGrrQ1spJ0B6HIzTDNEjRKnD4xyg4j\\ng01FMcJTU6E+V2JBY45CKN9dWr1JDM/nei/Pf0byBJlMp/mSSfjodykmz4Oe13xB\\nCa1WTwgFykKYthoLGYrmo+LKIGpMoeEbY1kuUe04UiDe47l6Oggwnl+8XD1MeRWY\\nsWgj8sF4dTcSfCMavK4zHRFFQbGp/YFJ/Ww6U9lA3Vq0wyEI6MCMQnoSMFwrbgZw\\nwwIDAQAB\n58199dcc:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3v8/ye/V/t5xf4JiXLXa\\nhWFRozsnmn3hobON20GdmkrzKzO/eUqPOKTpg2GtvBhK30fu5oY5uN2ORiv2Y2ht\\neLiZ9HVz3XP8Fm9frha60B7KNu66FO5P2o3i+E+DWTPqqPcCG6t4Znk2BypILcit\\nwiPKTsgbBQR2qo/cO01eLLdt6oOzAaF94NH0656kvRewdo6HG4urbO46tCAizvCR\\nCA7KGFMyad8WdKkTjxh8YLDLoOCtoZmXmQAiwfRe9pKXRH/XXGop8SYptLqyVVQ+\\ntegOD9wRs2tOlgcLx4F/uMzHN7uoho6okBPiifRX+Pf38Vx+ozXh056tjmdZkCaV\\naQIDAQAB\n58cbb476:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSPnuAGKtRIS5fEgYPXD\\n8pSGvKAmIv3A08LBViDUe+YwhilSHbYXUEAcSH1KZvOo1WT1x2FNEPBEFEFU1Eyc\\n+qGzbA03UFgBNvArurHQ5Z/GngGqE7IarSQFSoqewYRtFSfp+TL9CUNBvM0rT7vz\\n2eMu3/wWG+CBmb92lkmyWwC1WSWFKO3x8w+Br2IFWvAZqHRt8oiG5QtYvcZL6jym\\nY8T6sgdDlj+Y+wWaLHs9Fc+7vBuyK9C4O1ORdMPW15qVSl4Lc2Wu1QVwRiKnmA+c\\nDsH/m7kDNRHM7TjWnuj+nrBOKAHzYquiu5iB3Qmx+0gwnrSVf27Arc3ozUmmJbLj\\nzQIDAQAB\n58e4f17d:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvBxJN9ErBgdRcPr5g4hV\\nqyUSGZEKuvQliq2Z9SRHLh2J43+EdB6A+yzVvLnzcHVpBJ+BZ9RV30EM9guck9sh\\nr+bryZcRHyjG2wiIEoduxF2a8KeWeQH7QlpwGhuobo1+gA8L0AGImiA6UP3LOirl\\nI0G2+iaKZowME8/tydww4jx5vG132JCOScMjTalRsYZYJcjFbebQQolpqRaGB4iG\\nWqhytWQGWuKiB1A22wjmIYf3t96l1Mp+FmM2URPxD1gk/BIBnX7ew+2gWppXOK9j\\n1BJpo0/HaX5XoZ/uMqISAAtgHZAqq+g3IUPouxTphgYQRTRYpz2COw3NF43VYQrR\\nbQIDAQAB\n60ac2099:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR4uJVtJOnOFGchnMW5Y\\nj5/waBdG1u5BTMlH+iQMcV5+VgWhmpZHJCBz3ocD+0IGk2I68S5TDOHec/GSC0lv\\n6R9o6F7h429GmgPgVKQsc8mPTPtbjJMuLLs4xKc+viCplXc0Nc0ZoHmCH4da6fCV\\ntdpHQjVe6F9zjdquZ4RjV6R6JTiN9v924dGMAkbW/xXmamtz51FzondKC52Gh8Mo\\n/oA0/T0KsCMCi7tb4QNQUYrf+Xcha9uus4ww1kWNZyfXJB87a2kORLiWMfs2IBBJ\\nTmZ2Fnk0JnHDb8Oknxd9PvJPT0mvyT8DA+KIAPqNvOjUXP4bnjEHJcoCP9S5HkGC\\nIQIDAQAB\n6165ee59:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAutQkua2CAig4VFSJ7v54\\nALyu/J1WB3oni7qwCZD3veURw7HxpNAj9hR+S5N/pNeZgubQvJWyaPuQDm7PTs1+\\ntFGiYNfAsiibX6Rv0wci3M+z2XEVAeR9Vzg6v4qoofDyoTbovn2LztaNEjTkB+oK\\ntlvpNhg1zhou0jDVYFniEXvzjckxswHVb8cT0OMTKHALyLPrPOJzVtM9C1ew2Nnc\\n3848xLiApMu3NBk0JqfcS3Bo5Y2b1FRVBvdt+2gFoKZix1MnZdAEZ8xQzL/a0YS5\\nHd0wj5+EEKHfOd3A75uPa/WQmA+o0cBFfrzm69QDcSJSwGpzWrD1ScH3AK8nWvoj\\nv7e9gukK/9yl1b4fQQ00vttwJPSgm9EnfPHLAtgXkRloI27H6/PuLoNvSAMQwuCD\\nhQRlyGLPBETKkHeodfLoULjhDi1K2gKJTMhtbnUcAA7nEphkMhPWkBpgFdrH+5z4\\nLxy+3ek0cqcI7K68EtrffU8jtUj9LFTUC8dERaIBs7NgQ/LfDbDfGh9g6qVj1hZl\\nk9aaIPTm/xsi8v3u+0qaq7KzIBc9s59JOoA8TlpOaYdVgSQhHHLBaahOuAigH+VI\\nisbC9vmqsThF2QdDtQt37keuqoda2E6sL7PUvIyVXDRfwX7uMDjlzTxHTymvq2Ck\\nhtBqojBnThmjJQFgZXocHG8CAwEAAQ==\n61666e3f:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlEyxkHggKCXC2Wf5Mzx4\\nnZLFZvU2bgcA3exfNPO/g1YunKfQY+Jg4fr6tJUUTZ3XZUrhmLNWvpvSwDS19ZmC\\nIXOu0+V94aNgnhMsk9rr59I8qcbsQGIBoHzuAl8NzZCgdbEXkiY90w1skUw8J57z\\nqCsMBydAueMXuWqF5nGtYbi5vHwK42PffpiZ7G5Kjwn8nYMW5IZdL6ZnMEVJUWC9\\nI4waeKg0yskczYDmZUEAtrn3laX9677ToCpiKrvmZYjlGl0BaGp3cxggP2xaDbUq\\nqfFxWNgvUAb3pXD09JM6Mt6HSIJaFc9vQbrKB9KT515y763j5CC2KUsilszKi3mB\\nHYe5PoebdjS7D1Oh+tRqfegU2IImzSwW3iwA7PJvefFuc/kNIijfS/gH/cAqAK6z\\nbhdOtE/zc7TtqW2Wn5Y03jIZdtm12CxSxwgtCF1NPyEWyIxAQUX9ACb3M0FAZ61n\\nfpPrvwTaIIxxZ01L3IzPLpbc44x/DhJIEU+iDt6IMTrHOphD9MCG4631eIdB0H1b\\n6zbNX1CXTsafqHRFV9XmYYIeOMggmd90s3xIbEujA6HKNP/gwzO6CDJ+nHFDEqoF\\nSkxRdTkEqjTjVKieURW7Swv7zpfu5PrsrrkyGnsRrBJJzXlm2FOOxnbI2iSL1B5F\\nrO5kbUxFeZUIDq+7Yv4kLWcCAwEAAQ==\n616a9724:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnC+bR4bHf/L6QdU4puhQ\\ngl1MHePszRC38bzvVFDUJsmCaMCL2suCs2A2yxAgGb9pu9AJYLAmxQC4mM3jNqhg\\n/E7yuaBbek3O02zN/ctvflJ250wZCy+z0ZGIp1ak6pu1j14IwHokl9j36zNfGtfv\\nADVOcdpWITFFlPqwq1qt/H3UsKVmtiF3BNWWTeUEQwKvlU8ymxgS99yn0+4OPyNT\\nL3EUeS+NQJtDS01unau0t7LnjUXn+XIneWny8bIYOQCuVR6s/gpIGuhBaUqwaJOw\\n7jkJZYF2Ij7uPb4b5/R3vX2FfxxqEHqssFSg8FFUNTZz3qNZs0CRVyfA972g9WkJ\\nhPfn31pQYil4QGRibCMIeU27YAEjXoqfJKEPh4UWMQsQLrEfdGfb8VgwrPbniGfU\\nL3jKJR3VAafL9330iawzVQDlIlwGl6u77gEXMl9K0pfazunYhAp+BMP+9ot5ckK+\\nosmrqj11qMESsAj083GeFdfV3pXEIwUytaB0AKEht9DbqUfiE/oeZ/LAXgySMtVC\\nsbC4ESmgVeY2xSBIJdDyUap7FR49GGrw0W49NUv9gRgQtGGaNVQQO9oGL2PBC41P\\niWF9GLoX30HIz1P8PF/cZvicSSPkQf2Z6TV+t0ebdGNS5DjapdnCrq8m9Z0pyKsQ\\nuxAL2a7zX8l5i1CZh1ycUGsCAwEAAQ==\n616abc23:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0MfCDrhODRCIxR9Dep1s\\neXafh5CE5BrF4WbCgCsevyPIdvTeyIaW4vmO3bbG4VzhogDZju+R3IQYFuhoXP5v\\nY+zYJGnwrgz3r5wYAvPnLEs1+dtDKYOgJXQj+wLJBW1mzRDL8FoRXOe5iRmn1EFS\\nwZ1DoUvyu7/J5r0itKicZp3QKED6YoilXed+1vnS4Sk0mzN4smuMR9eO1mMCqNp9\\n9KTfRDHTbakIHwasECCXCp50uXdoW6ig/xUAFanpm9LtK6jctNDbXDhQmgvAaLXZ\\nLvFqoaYJ/CvWkyYCgL6qxvMvVmPoRv7OPcyni4xR/WgWa0MSaEWjgPx3+yj9fiMA\\n1S02pFWFDOr5OUF/O4YhFJvUCOtVsUPPfA/Lj6faL0h5QI9mQhy5Zb9TTaS9jB6p\\nLw7u0dJlrjFedk8KTJdFCcaGYHP6kNPnOxMylcB/5WcztXZVQD5WpCicGNBxCGMm\\nW64SgrV7M07gQfL/32QLsdqPUf0i8hoVD8wfQ3EpbQzv6Fk1Cn90bZqZafg8XWGY\\nwddhkXk7egrr23Djv37V2okjzdqoyLBYBxMz63qQzFoAVv5VoY2NDTbXYUYytOvG\\nGJ1afYDRVWrExCech1mX5ZVUB1br6WM+psFLJFoBFl6mDmiYt0vMYBddKISsvwLl\\nIJQkzDwtXzT2cSjoj3T5QekCAwEAAQ==\n616ac3bc:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvaaoSLab+IluixwKV5Od\\n0gib2YurjPatGIbn5Ov2DLUFYiebj2oJINXJSwUOO+4WcuHFEqiL/1rya+k5hLZt\\nhnPL1tn6QD4rESznvGSasRCQNT2vS/oyZbTYJRyAtFkEYLlq0t3S3xBxxHWuvIf0\\nqVxVNYpQWyM3N9RIeYBR/euXKJXileSHk/uq1I5wTC0XBIHWcthczGN0m9wBEiWS\\n0m3cnPk4q0Ea8mUJ91Rqob19qETz6VbSPYYpZk3qOycjKosuwcuzoMpwU8KRiMFd\\n5LHtX0Hx85ghGsWDVtS0c0+aJa4lOMGvJCAOvDfqvODv7gKlCXUpgumGpLdTmaZ8\\n1RwqspAe3IqBcdKTqRD4m2mSg23nVx2FAY3cjFvZQtfooT7q1ItRV5RgH6FhQSl7\\n+6YIMJ1Bf8AAlLdRLpg+doOUGcEn+pkDiHFgI8ylH1LKyFKw+eXaAml/7DaWZk1d\\ndqggwhXOhc/UUZFQuQQ8A8zpA13PcbC05XxN2hyP93tCEtyynMLVPtrRwDnHxFKa\\nqKzs3rMDXPSXRn3ZZTdKH3069ApkEjQdpcwUh+EmJ1Ve/5cdtzT6kKWCjKBFZP/s\\n91MlRrX2BTRdHaU5QJkUheUtakwxuHrdah2F94lRmsnQlpPr2YseJu6sIE+Dnx4M\\nCfhdVbQL2w54R645nlnohu8CAwEAAQ==\n616adfeb:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq0BFD1D4lIxQcsqEpQzU\\npNCYM3aP1V/fxxVdT4DWvSI53JHTwHQamKdMWtEXetWVbP5zSROniYKFXd/xrD9X\\n0jiGHey3lEtylXRIPxe5s+wXoCmNLcJVnvTcDtwx/ne2NLHxp76lyc25At+6RgE6\\nADjLVuoD7M4IFDkAsd8UQ8zM0Dww9SylIk/wgV3ZkifecvgUQRagrNUdUjR56EBZ\\nraQrev4hhzOgwelT0kXCu3snbUuNY/lU53CoTzfBJ5UfEJ5pMw1ij6X0r5S9IVsy\\nKLWH1hiO0NzU2c8ViUYCly4Fe9xMTFc6u2dy/dxf6FwERfGzETQxqZvSfrRX+GLj\\n/QZAXiPg5178hT/m0Y3z5IGenIC/80Z9NCi+byF1WuJlzKjDcF/TU72zk0+PNM/H\\nKuppf3JT4DyjiVzNC5YoWJT2QRMS9KLP5iKCSThwVceEEg5HfhQBRT9M6KIcFLSs\\nmFjx9kNEEmc1E8hl5IR3+3Ry8G5/bTIIruz14jgeY9u5jhL8Vyyvo41jgt9sLHR1\\n/J1TxKfkgksYev7PoX6/ZzJ1ksWKZY5NFoDXTNYUgzFUTOoEaOg3BAQKadb3Qbbq\\nXIrxmPBdgrn9QI7NCgfnAY3Tb4EEjs3ON/BNyEhUENcXOH6I1NbcuBQ7g9P73kE4\\nVORdoc8MdJ5eoKBpO8Ww8HECAwEAAQ==\n616ae350:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyduVzi1mWm+lYo2Tqt/0\\nXkCIWrDNP1QBMVPrE0/ZlU2bCGSoo2Z9FHQKz/mTyMRlhNqTfhJ5qU3U9XlyGOPJ\\npiM+b91g26pnpXJ2Q2kOypSgOMOPA4cQ42PkHBEqhuzssfj9t7x47ppS94bboh46\\nxLSDRff/NAbtwTpvhStV3URYkxFG++cKGGa5MPXBrxIp+iZf9GnuxVdST5PGiVGP\\nODL/b69sPJQNbJHVquqUTOh5Ry8uuD2WZuXfKf7/C0jC/ie9m2+0CttNu9tMciGM\\nEyKG1/Xhk5iIWO43m4SrrT2WkFlcZ1z2JSf9Pjm4C2+HovYpihwwdM/OdP8Xmsnr\\nDzVB4YvQiW+IHBjStHVuyiZWc+JsgEPJzisNY0Wyc/kNyNtqVKpX6dRhMLanLmy+\\nf53cCSI05KPQAcGj6tdL+D60uKDkt+FsDa0BTAobZ31OsFVid0vCXtsbplNhW1IF\\nHwsGXBTVcfXg44RLyL8Lk/2dQxDHNHzAUslJXzPxaHBLmt++2COa2EI1iWlvtznk\\nOk9WP8SOAIj+xdqoiHcC4j72BOVVgiITIJNHrbppZCq6qPR+fgXmXa+sDcGh30m6\\n9Wpbr28kLMSHiENCWTdsFij+NQTd5S47H7XTROHnalYDuF1RpS+DpQidT5tUimaT\\nJZDr++FjKrnnijbyNF8b98UCAwEAAQ==\n616db30d:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpUpyWDWjlUk3smlWeA0\\nlIMW+oJ38t92CRLHH3IqRhyECBRW0d0aRGtq7TY8PmxjjvBZrxTNDpJT6KUk4LRm\\na6A6IuAI7QnNK8SJqM0DLzlpygd7GJf8ZL9SoHSH+gFsYF67Cpooz/YDqWrlN7Vw\\ntO00s0B+eXy+PCXYU7VSfuWFGK8TGEv6HfGMALLjhqMManyvfp8hz3ubN1rK3c8C\\nUS/ilRh1qckdbtPvoDPhSbTDmfU1g/EfRSIEXBrIMLg9ka/XB9PvWRrekrppnQzP\\nhP9YE3x/wbFc5QqQWiRCYyQl/rgIMOXvIxhkfe8H5n1Et4VAorkpEAXdsfN8KSVv\\nLSMazVlLp9GYq5SUpqYX3KnxdWBgN7BJoZ4sltsTpHQ/34SXWfu3UmyUveWj7wp0\\nx9hwsPirVI00EEea9AbP7NM2rAyu6ukcm4m6ATd2DZJIViq2es6m60AE6SMCmrQF\\nwmk4H/kdQgeAELVfGOm2VyJ3z69fQuywz7xu27S6zTKi05Qlnohxol4wVb6OB7qG\\nLPRtK9ObgzRo/OPumyXqlzAi/Yvyd1ZQk8labZps3e16bQp8+pVPiumWioMFJDWV\\nGZjCmyMSU8V6MB6njbgLHoyg2LCukCAeSjbPGGGYhnKLm1AKSoJh3IpZuqcKCk5C\\n8CM1S15HxV78s9dFntEqIokCAwEAAQ==\n66ba20fe:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtfB12w4ZgqsXWZDfUAV/\\n6Y4aHUKIu3q4SXrNZ7CXF9nXoAVYrS7NAxJdAodsY3vPCN0g5O8DFXR+390LdOuQ\\n+HsGKCc1k5tX5ZXld37EZNTNSbR0k+NKhd9h6X3u6wqPOx7SIKxwAQR8qeeFq4pP\\nrt9GAGlxtuYgzIIcKJPwE0dZlcBCg+GnptCUZXp/38BP1eYC+xTXSL6Muq1etYfg\\nodXdb7Yl+2h1IHuOwo5rjgY5kpY7GcAs8AjGk3lDD/av60OTYccknH0NCVSmPoXK\\nvrxDBOn0LQRNBLcAfnTKgHrzy0Q5h4TNkkyTgxkoQw5ObDk9nnabTxql732yy9BY\\ns+hM9+dSFO1HKeVXreYSA2n1ndF18YAvAumzgyqzB7I4pMHXq1kC/8bONMJxwSkS\\nYm6CoXKyavp7RqGMyeVpRC7tV+blkrrUml0BwNkxE+XnwDRB3xDV6hqgWe0XrifD\\nYTfvd9ScZQP83ip0r4IKlq4GMv/R5shcCRJSkSZ6QSGshH40JYSoiwJf5FHbj9ND\\n7do0UAqebWo4yNx63j/wb2ULorW3AClv0BCFSdPsIrCStiGdpgJDBR2P2NZOCob3\\nG9uMj+wJD6JJg2nWqNJxkANXX37Qf8plgzssrhrgOvB0fjjS7GYhfkfmZTJ0wPOw\\nA8+KzFseBh4UFGgue78KwgkCAwEAAQ==\n'\n__Keyring=\n__KeyringFile=\"/usr/share/keyrings/ubuntu-archive-keyring.gpg\"\n__SkipSigCheck=0\n__SkipEmulation=0\n__UseMirror=0\n\n__UnprocessedBuildArgs=\nwhile :; do\n    if [[ \"$#\" -le 0 ]]; then\n        break\n    fi\n\n    lowerI=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case $lowerI in\n        -\\?|-h|--help)\n            usage\n            ;;\n        arm)\n            __BuildArch=arm\n            __UbuntuArch=armhf\n            __AlpineArch=armv7\n            __QEMUArch=arm\n            ;;\n        arm64)\n            __BuildArch=arm64\n            __UbuntuArch=arm64\n            __AlpineArch=aarch64\n            __QEMUArch=aarch64\n            __FreeBSDArch=arm64\n            __FreeBSDMachineArch=aarch64\n            ;;\n        armel)\n            __BuildArch=armel\n            __UbuntuArch=armel\n            __UbuntuRepo=\"http://archive.debian.org/debian/\"\n            __CodeName=buster\n            __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n            __LLDB_Package=\"liblldb-6.0-dev\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp-dev/}\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp5/}\"\n            __UbuntuSuites=\n            ;;\n        armv6)\n            __BuildArch=armv6\n            __UbuntuArch=armhf\n            __QEMUArch=arm\n            __UbuntuRepo=\"http://raspbian.raspberrypi.org/raspbian/\"\n            __CodeName=buster\n            __KeyringFile=\"/usr/share/keyrings/raspbian-archive-keyring.gpg\"\n            __LLDB_Package=\"liblldb-6.0-dev\"\n            __UbuntuSuites=\n\n            if [[ -e \"$__KeyringFile\" ]]; then\n                __Keyring=\"--keyring $__KeyringFile\"\n            fi\n            ;;\n        loongarch64)\n            __BuildArch=loongarch64\n            __AlpineArch=loongarch64\n            __QEMUArch=loongarch64\n            __UbuntuArch=loong64\n            __UbuntuSuites=unreleased\n            __LLDB_Package=\"liblldb-19-dev\"\n\n            if [[ \"$__CodeName\" == \"sid\" ]]; then\n                __UbuntuRepo=\"http://ftp.ports.debian.org/debian-ports/\"\n            fi\n            ;;\n        riscv64)\n            __BuildArch=riscv64\n            __AlpineArch=riscv64\n            __AlpinePackages=\"${__AlpinePackages// lldb-dev/}\"\n            __QEMUArch=riscv64\n            __UbuntuArch=riscv64\n            __UbuntuPackages=\"${__UbuntuPackages// libunwind8-dev/}\"\n            unset __LLDB_Package\n            ;;\n        ppc64le)\n            __BuildArch=ppc64le\n            __AlpineArch=ppc64le\n            __QEMUArch=ppc64le\n            __UbuntuArch=ppc64el\n            __UbuntuRepo=\"http://ports.ubuntu.com/ubuntu-ports/\"\n            __UbuntuPackages=\"${__UbuntuPackages// libunwind8-dev/}\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp-dev/}\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp5/}\"\n            unset __LLDB_Package\n            ;;\n        s390x)\n            __BuildArch=s390x\n            __AlpineArch=s390x\n            __QEMUArch=s390x\n            __UbuntuArch=s390x\n            __UbuntuRepo=\"http://ports.ubuntu.com/ubuntu-ports/\"\n            __UbuntuPackages=\"${__UbuntuPackages// libunwind8-dev/}\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp-dev/}\"\n            __UbuntuPackages=\"${__UbuntuPackages// libomp5/}\"\n            unset __LLDB_Package\n            ;;\n        x64)\n            __BuildArch=x64\n            __AlpineArch=x86_64\n            __UbuntuArch=amd64\n            __FreeBSDArch=amd64\n            __FreeBSDMachineArch=amd64\n            __illumosArch=x86_64\n            __HaikuArch=x86_64\n            __UbuntuRepo=\"http://archive.ubuntu.com/ubuntu/\"\n            ;;\n        x86)\n            __BuildArch=x86\n            __UbuntuArch=i386\n            __AlpineArch=x86\n            __UbuntuRepo=\"http://archive.ubuntu.com/ubuntu/\"\n            ;;\n        lldb*)\n            version=\"$(echo \"$lowerI\" | tr -d '[:alpha:]-=')\"\n            majorVersion=\"${version%%.*}\"\n\n            [ -z \"${version##*.*}\" ] && minorVersion=\"${version#*.}\"\n            if [ -z \"$minorVersion\" ]; then\n                minorVersion=0\n            fi\n\n            # for versions > 6.0, lldb has dropped the minor version\n            if [ \"$majorVersion\" -le 6 ]; then\n                version=\"$majorVersion.$minorVersion\"\n            else\n                version=\"$majorVersion\"\n            fi\n\n            __LLDB_Package=\"liblldb-${version}-dev\"\n            ;;\n        no-lldb)\n            unset __LLDB_Package\n            ;;\n        llvm*)\n            version=\"$(echo \"$lowerI\" | tr -d '[:alpha:]-=')\"\n            __LLVM_MajorVersion=\"${version%%.*}\"\n\n            [ -z \"${version##*.*}\" ] && __LLVM_MinorVersion=\"${version#*.}\"\n            if [ -z \"$__LLVM_MinorVersion\" ]; then\n                __LLVM_MinorVersion=0\n            fi\n\n            # for versions > 6.0, lldb has dropped the minor version\n            if [ \"$__LLVM_MajorVersion\" -gt 6 ]; then\n                __LLVM_MinorVersion=\n            fi\n\n            ;;\n        xenial) # Ubuntu 16.04\n            __CodeName=xenial\n            ;;\n        bionic) # Ubuntu 18.04\n            __CodeName=bionic\n            ;;\n        focal) # Ubuntu 20.04\n            __CodeName=focal\n            ;;\n        jammy) # Ubuntu 22.04\n            __CodeName=jammy\n            ;;\n        noble) # Ubuntu 24.04\n            __CodeName=noble\n            if [[ -z \"$__LLDB_Package\" ]]; then\n                __LLDB_Package=\"liblldb-19-dev\"\n            fi\n            ;;\n        stretch) # Debian 9\n            __CodeName=stretch\n            __LLDB_Package=\"liblldb-6.0-dev\"\n            __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n\n            if [[ -z \"$__UbuntuRepo\" ]]; then\n                __UbuntuRepo=\"http://ftp.debian.org/debian/\"\n            fi\n            ;;\n        buster) # Debian 10\n            __CodeName=buster\n            __LLDB_Package=\"liblldb-6.0-dev\"\n            __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n\n            if [[ -z \"$__UbuntuRepo\" ]]; then\n                __UbuntuRepo=\"http://archive.debian.org/debian/\"\n            fi\n            ;;\n        bullseye) # Debian 11\n            __CodeName=bullseye\n            __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n\n            if [[ -z \"$__UbuntuRepo\" ]]; then\n                __UbuntuRepo=\"http://ftp.debian.org/debian/\"\n            fi\n            ;;\n        bookworm) # Debian 12\n            __CodeName=bookworm\n            __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n\n            if [[ -z \"$__UbuntuRepo\" ]]; then\n                __UbuntuRepo=\"http://ftp.debian.org/debian/\"\n            fi\n            ;;\n        sid) # Debian sid\n            __CodeName=sid\n            __UbuntuSuites=\n\n            # Debian-Ports architectures need different values\n            case \"$__UbuntuArch\" in\n            amd64|arm64|armel|armhf|i386|mips64el|ppc64el|riscv64|s390x)\n                __KeyringFile=\"/usr/share/keyrings/debian-archive-keyring.gpg\"\n\n                if [[ -z \"$__UbuntuRepo\" ]]; then\n                    __UbuntuRepo=\"http://ftp.debian.org/debian/\"\n                fi\n                ;;\n            *)\n                __KeyringFile=\"/usr/share/keyrings/debian-ports-archive-keyring.gpg\"\n\n                if [[ -z \"$__UbuntuRepo\" ]]; then\n                    __UbuntuRepo=\"http://ftp.ports.debian.org/debian-ports/\"\n                fi\n                ;;\n            esac\n\n            if [[ -e \"$__KeyringFile\" ]]; then\n                __Keyring=\"--keyring $__KeyringFile\"\n            fi\n            ;;\n        tizen)\n            __CodeName=\n            __UbuntuRepo=\n            __Tizen=tizen\n            ;;\n        alpine*)\n            __CodeName=alpine\n            __UbuntuRepo=\n\n            if [[ \"$lowerI\" == \"alpineedge\" ]]; then\n                __AlpineVersion=edge\n            else\n                version=\"$(echo \"$lowerI\" | tr -d '[:alpha:]-=')\"\n                __AlpineMajorVersion=\"${version%%.*}\"\n                __AlpineMinorVersion=\"${version#*.}\"\n                __AlpineVersion=\"$__AlpineMajorVersion.$__AlpineMinorVersion\"\n            fi\n            ;;\n        freebsd13)\n            __CodeName=freebsd\n            __SkipUnmount=1\n            ;;\n        freebsd14)\n            __CodeName=freebsd\n            __FreeBSDBase=\"14.2-RELEASE\"\n            __FreeBSDABI=\"14\"\n            __SkipUnmount=1\n            ;;\n        illumos)\n            __CodeName=illumos\n            __SkipUnmount=1\n            ;;\n        haiku)\n            __CodeName=haiku\n            __SkipUnmount=1\n            ;;\n        --skipunmount)\n            __SkipUnmount=1\n            ;;\n        --skipsigcheck)\n            __SkipSigCheck=1\n            ;;\n        --skipemulation)\n            __SkipEmulation=1\n            ;;\n        --rootfsdir|-rootfsdir)\n            shift\n            __RootfsDir=\"$1\"\n            ;;\n        --use-mirror)\n            __UseMirror=1\n            ;;\n        --use-jobs)\n            shift\n            MAXJOBS=$1\n            ;;\n        *)\n            __UnprocessedBuildArgs=\"$__UnprocessedBuildArgs $1\"\n            ;;\n    esac\n\n    shift\ndone\n\ncase \"$__AlpineVersion\" in\n    3.14) __AlpinePackages+=\" llvm11-libs\" ;;\n    3.15) __AlpinePackages+=\" llvm12-libs\" ;;\n    3.16) __AlpinePackages+=\" llvm13-libs\" ;;\n    3.17) __AlpinePackages+=\" llvm15-libs\" ;;\n    edge) __AlpineLlvmLibsLookup=1 ;;\n    *)\n        if [[ \"$__AlpineArch\" =~ s390x|ppc64le ]]; then\n            __AlpineVersion=3.15 # minimum version that supports lldb-dev\n            __AlpinePackages+=\" llvm12-libs\"\n        elif [[ \"$__AlpineArch\" == \"x86\" ]]; then\n            __AlpineVersion=3.17 # minimum version that supports lldb-dev\n            __AlpinePackages+=\" llvm15-libs\"\n        elif [[ \"$__AlpineArch\" == \"riscv64\" || \"$__AlpineArch\" == \"loongarch64\" ]]; then\n            __AlpineVersion=3.21 # minimum version that supports lldb-dev\n            __AlpinePackages+=\" llvm19-libs\"\n        elif [[ -n \"$__AlpineMajorVersion\" ]]; then\n            # use whichever alpine version is provided and select the latest toolchain libs\n            __AlpineLlvmLibsLookup=1\n        else\n            __AlpineVersion=3.13 # 3.13 to maximize compatibility\n            __AlpinePackages+=\" llvm10-libs\"\n        fi\nesac\n\nif [[ \"$__AlpineVersion\" =~ 3\\.1[345] ]]; then\n    # compiler-rt--static was merged in compiler-rt package in alpine 3.16\n    # for older versions, we need compiler-rt--static, so replace the name\n    __AlpinePackages=\"${__AlpinePackages/compiler-rt/compiler-rt-static}\"\nfi\n\n__UbuntuPackages+=\" ${__LLDB_Package:-}\"\n\nif [[ -z \"$__UbuntuRepo\" ]]; then\n    __UbuntuRepo=\"http://ports.ubuntu.com/\"\nfi\n\nif [[ -n \"$__LLVM_MajorVersion\" ]]; then\n    __UbuntuPackages+=\" libclang-common-${__LLVM_MajorVersion}${__LLVM_MinorVersion:+.$__LLVM_MinorVersion}-dev\"\nfi\n\nif [[ -z \"$__RootfsDir\" && -n \"$ROOTFS_DIR\" ]]; then\n    __RootfsDir=\"$ROOTFS_DIR\"\nfi\n\nif [[ -z \"$__RootfsDir\" ]]; then\n    __RootfsDir=\"$__CrossDir/../../../.tools/rootfs/$__BuildArch\"\nfi\n\nif [[ -d \"$__RootfsDir\" ]]; then\n    if [[ \"$__SkipUnmount\" == \"0\" ]]; then\n        umount \"$__RootfsDir\"/* || true\n    fi\n    rm -rf \"$__RootfsDir\"\nfi\n\nmkdir -p \"$__RootfsDir\"\n__RootfsDir=\"$( cd \"$__RootfsDir\" && pwd )\"\n\n__hasWget=\nensureDownloadTool()\n{\n    if command -v wget &> /dev/null; then\n        __hasWget=1\n    elif command -v curl &> /dev/null; then\n        __hasWget=0\n    else\n        >&2 echo \"ERROR: either wget or curl is required by this script.\"\n        exit 1\n    fi\n}\n\nif [[ \"$__CodeName\" == \"alpine\" ]]; then\n    __ApkToolsVersion=2.12.11\n    __ApkToolsDir=\"$(mktemp -d)\"\n    __ApkKeysDir=\"$(mktemp -d)\"\n    arch=\"$(uname -m)\"\n\n    ensureDownloadTool\n\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -P \"$__ApkToolsDir\" \"https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v$__ApkToolsVersion/$arch/apk.static\"\n    else\n        curl -SLO --create-dirs --output-dir \"$__ApkToolsDir\" \"https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v$__ApkToolsVersion/$arch/apk.static\"\n    fi\n    if [[ \"$arch\" == \"x86_64\" ]]; then\n      __ApkToolsSHA512SUM=\"53e57b49230da07ef44ee0765b9592580308c407a8d4da7125550957bb72cb59638e04f8892a18b584451c8d841d1c7cb0f0ab680cc323a3015776affaa3be33\"\n    elif [[ \"$arch\" == \"aarch64\" ]]; then\n      __ApkToolsSHA512SUM=\"9e2b37ecb2b56c05dad23d379be84fd494c14bd730b620d0d576bda760588e1f2f59a7fcb2f2080577e0085f23a0ca8eadd993b4e61c2ab29549fdb71969afd0\"\n    else\n      echo \"WARNING: add missing hash for your host architecture. To find the value, use: 'find /tmp -name apk.static -exec sha512sum {} \\;'\"\n    fi\n    echo \"$__ApkToolsSHA512SUM $__ApkToolsDir/apk.static\" | sha512sum -c\n    chmod +x \"$__ApkToolsDir/apk.static\"\n\n    if [[ \"$__AlpineVersion\" == \"edge\" ]]; then\n        version=edge\n    else\n        version=\"v$__AlpineVersion\"\n    fi\n\n    for line in $__AlpineKeys; do\n        id=\"${line%%:*}\"\n        content=\"${line#*:}\"\n\n        echo -e \"-----BEGIN PUBLIC KEY-----\\n$content\\n-----END PUBLIC KEY-----\" > \"$__ApkKeysDir/alpine-devel@lists.alpinelinux.org-$id.rsa.pub\"\n    done\n\n    if [[ \"$__SkipSigCheck\" == \"1\" ]]; then\n        __ApkSignatureArg=\"--allow-untrusted\"\n    else\n        __ApkSignatureArg=\"--keys-dir $__ApkKeysDir\"\n    fi\n\n    if [[ \"$__SkipEmulation\" == \"1\" ]]; then\n        __NoEmulationArg=\"--no-scripts\"\n    fi\n\n    # initialize DB\n    # shellcheck disable=SC2086\n    \"$__ApkToolsDir/apk.static\" \\\n        -X \"http://dl-cdn.alpinelinux.org/alpine/$version/main\" \\\n        -X \"http://dl-cdn.alpinelinux.org/alpine/$version/community\" \\\n        -U $__ApkSignatureArg --root \"$__RootfsDir\" --arch \"$__AlpineArch\" --initdb add\n\n    if [[ \"$__AlpineLlvmLibsLookup\" == 1 ]]; then\n        # shellcheck disable=SC2086\n        __AlpinePackages+=\" $(\"$__ApkToolsDir/apk.static\" \\\n            -X \"http://dl-cdn.alpinelinux.org/alpine/$version/main\" \\\n            -X \"http://dl-cdn.alpinelinux.org/alpine/$version/community\" \\\n            -U $__ApkSignatureArg --root \"$__RootfsDir\" --arch \"$__AlpineArch\" \\\n            search 'llvm*-libs' | grep -E '^llvm' | sort | tail -1 | sed 's/-[^-]*//2g')\"\n    fi\n\n    # install all packages in one go\n    # shellcheck disable=SC2086\n    \"$__ApkToolsDir/apk.static\" \\\n        -X \"http://dl-cdn.alpinelinux.org/alpine/$version/main\" \\\n        -X \"http://dl-cdn.alpinelinux.org/alpine/$version/community\" \\\n        -U $__ApkSignatureArg --root \"$__RootfsDir\" --arch \"$__AlpineArch\" $__NoEmulationArg \\\n        add $__AlpinePackages\n\n    rm -r \"$__ApkToolsDir\"\nelif [[ \"$__CodeName\" == \"freebsd\" ]]; then\n    mkdir -p \"$__RootfsDir\"/usr/local/etc\n    JOBS=${MAXJOBS:=\"$(getconf _NPROCESSORS_ONLN)\"}\n\n    ensureDownloadTool\n\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O- \"https://download.freebsd.org/ftp/releases/${__FreeBSDArch}/${__FreeBSDMachineArch}/${__FreeBSDBase}/base.txz\" | tar -C \"$__RootfsDir\" -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version\n    else\n        curl -SL \"https://download.freebsd.org/ftp/releases/${__FreeBSDArch}/${__FreeBSDMachineArch}/${__FreeBSDBase}/base.txz\" | tar -C \"$__RootfsDir\" -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version\n    fi\n    echo \"ABI = \\\"FreeBSD:${__FreeBSDABI}:${__FreeBSDMachineArch}\\\"; FINGERPRINTS = \\\"${__RootfsDir}/usr/share/keys\\\"; REPOS_DIR = [\\\"${__RootfsDir}/etc/pkg\\\"]; REPO_AUTOUPDATE = NO; RUN_SCRIPTS = NO;\" > \"${__RootfsDir}\"/usr/local/etc/pkg.conf\n    echo \"FreeBSD: { url: \\\"pkg+http://pkg.FreeBSD.org/\\${ABI}/quarterly\\\", mirror_type: \\\"srv\\\", signature_type: \\\"fingerprints\\\", fingerprints: \\\"/usr/share/keys/pkg\\\", enabled: yes }\" > \"${__RootfsDir}\"/etc/pkg/FreeBSD.conf\n    mkdir -p \"$__RootfsDir\"/tmp\n    # get and build package manager\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O- \"https://github.com/freebsd/pkg/archive/${__FreeBSDPkg}.tar.gz\" | tar -C \"$__RootfsDir\"/tmp -zxf -\n    else\n        curl -SL \"https://github.com/freebsd/pkg/archive/${__FreeBSDPkg}.tar.gz\" | tar -C \"$__RootfsDir\"/tmp -zxf -\n    fi\n    cd \"$__RootfsDir/tmp/pkg-${__FreeBSDPkg}\"\n    # needed for install to succeed\n    mkdir -p \"$__RootfsDir\"/host/etc\n    ./autogen.sh && ./configure --prefix=\"$__RootfsDir\"/host && make -j \"$JOBS\" && make install\n    rm -rf \"$__RootfsDir/tmp/pkg-${__FreeBSDPkg}\"\n    # install packages we need.\n    INSTALL_AS_USER=$(whoami) \"$__RootfsDir\"/host/sbin/pkg -r \"$__RootfsDir\" -C \"$__RootfsDir\"/usr/local/etc/pkg.conf update\n    # shellcheck disable=SC2086\n    INSTALL_AS_USER=$(whoami) \"$__RootfsDir\"/host/sbin/pkg -r \"$__RootfsDir\" -C \"$__RootfsDir\"/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages\nelif [[ \"$__CodeName\" == \"illumos\" ]]; then\n    mkdir \"$__RootfsDir/tmp\"\n    pushd \"$__RootfsDir/tmp\"\n    JOBS=${MAXJOBS:=\"$(getconf _NPROCESSORS_ONLN)\"}\n\n    ensureDownloadTool\n\n    echo \"Downloading sysroot.\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O- https://github.com/illumos/sysroot/releases/download/20181213-de6af22ae73b-v1/illumos-sysroot-i386-20181213-de6af22ae73b-v1.tar.gz | tar -C \"$__RootfsDir\" -xzf -\n    else\n        curl -SL https://github.com/illumos/sysroot/releases/download/20181213-de6af22ae73b-v1/illumos-sysroot-i386-20181213-de6af22ae73b-v1.tar.gz | tar -C \"$__RootfsDir\" -xzf -\n    fi\n    echo \"Building binutils. Please wait..\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O- https://ftp.gnu.org/gnu/binutils/binutils-2.42.tar.xz | tar -xJf -\n    else\n        curl -SL https://ftp.gnu.org/gnu/binutils/binutils-2.42.tar.xz | tar -xJf -\n    fi\n    mkdir build-binutils && cd build-binutils\n    ../binutils-2.42/configure --prefix=\"$__RootfsDir\" --target=\"${__illumosArch}-sun-solaris2.11\" --program-prefix=\"${__illumosArch}-illumos-\" --with-sysroot=\"$__RootfsDir\"\n    make -j \"$JOBS\" && make install && cd ..\n    echo \"Building gcc. Please wait..\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O- https://ftp.gnu.org/gnu/gcc/gcc-13.3.0/gcc-13.3.0.tar.xz | tar -xJf -\n    else\n        curl -SL https://ftp.gnu.org/gnu/gcc/gcc-13.3.0/gcc-13.3.0.tar.xz | tar -xJf -\n    fi\n    CFLAGS=\"-fPIC\"\n    CXXFLAGS=\"-fPIC\"\n    CXXFLAGS_FOR_TARGET=\"-fPIC\"\n    CFLAGS_FOR_TARGET=\"-fPIC\"\n    export CFLAGS CXXFLAGS CXXFLAGS_FOR_TARGET CFLAGS_FOR_TARGET\n    mkdir build-gcc && cd build-gcc\n    ../gcc-13.3.0/configure --prefix=\"$__RootfsDir\" --target=\"${__illumosArch}-sun-solaris2.11\" --program-prefix=\"${__illumosArch}-illumos-\" --with-sysroot=\"$__RootfsDir\" --with-gnu-as       \\\n        --with-gnu-ld --disable-nls --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libcilkrts --disable-libada --disable-libsanitizer \\\n        --disable-libquadmath-support --disable-shared --enable-tls\n    make -j \"$JOBS\" && make install && cd ..\n    BaseUrl=https://pkgsrc.smartos.org\n    if [[ \"$__UseMirror\" == 1 ]]; then\n        BaseUrl=https://pkgsrc.smartos.skylime.net\n    fi\n    BaseUrl=\"$BaseUrl/packages/SmartOS/2019Q4/${__illumosArch}/All\"\n    echo \"Downloading manifest\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget \"$BaseUrl\"\n    else\n        curl -SLO \"$BaseUrl\"\n    fi\n    echo \"Downloading dependencies.\"\n    read -ra array <<<\"$__IllumosPackages\"\n    for package in \"${array[@]}\"; do\n        echo \"Installing '$package'\"\n        # find last occurrence of package in listing and extract its name\n        package=\"$(sed -En '/.*href=\"('\"$package\"'-[0-9].*).tgz\".*/h;$!d;g;s//\\1/p' All)\"\n        echo \"Resolved name '$package'\"\n        if [[ \"$__hasWget\" == 1 ]]; then\n            wget \"$BaseUrl\"/\"$package\".tgz\n        else\n            curl -SLO \"$BaseUrl\"/\"$package\".tgz\n        fi\n        ar -x \"$package\".tgz\n        tar --skip-old-files -xzf \"$package\".tmp.tg* -C \"$__RootfsDir\" 2>/dev/null\n    done\n    echo \"Cleaning up temporary files.\"\n    popd\n    rm -rf \"$__RootfsDir\"/{tmp,+*}\n    mkdir -p \"$__RootfsDir\"/usr/include/net\n    mkdir -p \"$__RootfsDir\"/usr/include/netpacket\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -P \"$__RootfsDir\"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/bpf.h\n        wget -P \"$__RootfsDir\"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/dlt.h\n        wget -P \"$__RootfsDir\"/usr/include/netpacket https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/inet/sockmods/netpacket/packet.h\n        wget -P \"$__RootfsDir\"/usr/include/sys https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/sys/sdt.h\n    else\n        curl -SLO --create-dirs --output-dir \"$__RootfsDir\"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/bpf.h\n        curl -SLO --create-dirs --output-dir \"$__RootfsDir\"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/dlt.h\n        curl -SLO --create-dirs --output-dir \"$__RootfsDir\"/usr/include/netpacket https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/inet/sockmods/netpacket/packet.h\n        curl -SLO --create-dirs --output-dir \"$__RootfsDir\"/usr/include/sys https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/sys/sdt.h\n    fi\nelif [[ \"$__CodeName\" == \"haiku\" ]]; then\n    JOBS=${MAXJOBS:=\"$(getconf _NPROCESSORS_ONLN)\"}\n\n    echo \"Building Haiku sysroot for $__HaikuArch\"\n    mkdir -p \"$__RootfsDir/tmp\"\n    pushd \"$__RootfsDir/tmp\"\n\n    mkdir \"$__RootfsDir/tmp/download\"\n\n    ensureDownloadTool\n\n    echo \"Downloading Haiku package tools\"\n    git clone https://github.com/haiku/haiku-toolchains-ubuntu --depth 1 \"$__RootfsDir/tmp/script\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O \"$__RootfsDir/tmp/download/hosttools.zip\" \"$(\"$__RootfsDir/tmp/script/fetch.sh\" --hosttools)\"\n    else\n        curl -SLo \"$__RootfsDir/tmp/download/hosttools.zip\" \"$(\"$__RootfsDir/tmp/script/fetch.sh\" --hosttools)\"\n    fi\n\n    unzip -o \"$__RootfsDir/tmp/download/hosttools.zip\" -d \"$__RootfsDir/tmp/bin\"\n\n    HaikuBaseUrl=\"https://eu.hpkg.haiku-os.org/haiku/master/$__HaikuArch/current\"\n    HaikuPortsBaseUrl=\"https://eu.hpkg.haiku-os.org/haikuports/master/$__HaikuArch/current\"\n\n    echo \"Downloading HaikuPorts package repository index...\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -P \"$__RootfsDir/tmp/download\" \"$HaikuPortsBaseUrl/repo\"\n    else\n        curl -SLO --create-dirs --output-dir \"$__RootfsDir/tmp/download\" \"$HaikuPortsBaseUrl/repo\"\n    fi\n\n    echo \"Downloading Haiku packages\"\n    read -ra array <<<\"$__HaikuPackages\"\n    for package in \"${array[@]}\"; do\n        echo \"Downloading $package...\"\n        hpkgFilename=\"$(LD_LIBRARY_PATH=\"$__RootfsDir/tmp/bin\" \"$__RootfsDir/tmp/bin/package_repo\" list -f \"$__RootfsDir/tmp/download/repo\" |\n            grep -E \"${package}-\" | sort -V | tail -n 1 | xargs)\"\n        if [ -z \"$hpkgFilename\" ]; then\n            >&2 echo \"ERROR: package $package missing.\"\n            exit 1\n        fi\n        echo \"Resolved filename: $hpkgFilename...\"\n        hpkgDownloadUrl=\"$HaikuPortsBaseUrl/packages/$hpkgFilename\"\n        if [[ \"$__hasWget\" == 1 ]]; then\n            wget -P \"$__RootfsDir/tmp/download\" \"$hpkgDownloadUrl\"\n        else\n            curl -SLO --create-dirs --output-dir \"$__RootfsDir/tmp/download\" \"$hpkgDownloadUrl\"\n        fi\n    done\n    for package in haiku haiku_devel; do\n        echo \"Downloading $package...\"\n        if [[ \"$__hasWget\" == 1 ]]; then\n            hpkgVersion=\"$(wget -qO- \"$HaikuBaseUrl\" | sed -n 's/^.*version: \"\\([^\"]*\\)\".*$/\\1/p')\"\n            wget -P \"$__RootfsDir/tmp/download\" \"$HaikuBaseUrl/packages/$package-$hpkgVersion-1-$__HaikuArch.hpkg\"\n        else\n            hpkgVersion=\"$(curl -sSL \"$HaikuBaseUrl\" | sed -n 's/^.*version: \"\\([^\"]*\\)\".*$/\\1/p')\"\n            curl -SLO --create-dirs --output-dir \"$__RootfsDir/tmp/download\" \"$HaikuBaseUrl/packages/$package-$hpkgVersion-1-$__HaikuArch.hpkg\"\n        fi\n    done\n\n    # Set up the sysroot\n    echo \"Setting up sysroot and extracting required packages\"\n    mkdir -p \"$__RootfsDir/boot/system\"\n    for file in \"$__RootfsDir/tmp/download/\"*.hpkg; do\n        echo \"Extracting $file...\"\n        LD_LIBRARY_PATH=\"$__RootfsDir/tmp/bin\" \"$__RootfsDir/tmp/bin/package\" extract -C \"$__RootfsDir/boot/system\" \"$file\"\n    done\n\n    # Download buildtools\n    echo \"Downloading Haiku buildtools\"\n    if [[ \"$__hasWget\" == 1 ]]; then\n        wget -O \"$__RootfsDir/tmp/download/buildtools.zip\" \"$(\"$__RootfsDir/tmp/script/fetch.sh\" --buildtools --arch=$__HaikuArch)\"\n    else\n        curl -SLo \"$__RootfsDir/tmp/download/buildtools.zip\" \"$(\"$__RootfsDir/tmp/script/fetch.sh\" --buildtools --arch=$__HaikuArch)\"\n    fi\n    unzip -o \"$__RootfsDir/tmp/download/buildtools.zip\" -d \"$__RootfsDir\"\n\n    # Cleaning up temporary files\n    echo \"Cleaning up temporary files\"\n    popd\n    rm -rf \"$__RootfsDir/tmp\"\nelif [[ -n \"$__CodeName\" ]]; then\n    __Suites=\"$__CodeName $(for suite in $__UbuntuSuites; do echo -n \"$__CodeName-$suite \"; done)\"\n\n    if [[ \"$__SkipEmulation\" == \"1\" ]]; then\n        if [[ -z \"$AR\" ]]; then\n            if command -v ar &>/dev/null; then\n                AR=\"$(command -v ar)\"\n            elif command -v llvm-ar &>/dev/null; then\n                AR=\"$(command -v llvm-ar)\"\n            else\n                echo \"Unable to find ar or llvm-ar on PATH, add them to PATH or set AR environment variable pointing to the available AR tool\"\n                exit 1\n            fi\n        fi\n\n        PYTHON=${PYTHON_EXECUTABLE:-python3}\n\n        # shellcheck disable=SC2086,SC2046\n        echo running \"$PYTHON\" \"$__CrossDir/install-debs.py\" --arch \"$__UbuntuArch\" --mirror \"$__UbuntuRepo\" --rootfsdir \"$__RootfsDir\" --artool \"$AR\" \\\n            $(for suite in $__Suites; do echo -n \"--suite $suite \"; done) \\\n            $__UbuntuPackages\n\n        # shellcheck disable=SC2086,SC2046\n        \"$PYTHON\" \"$__CrossDir/install-debs.py\" --arch \"$__UbuntuArch\" --mirror \"$__UbuntuRepo\" --rootfsdir \"$__RootfsDir\" --artool \"$AR\" \\\n            $(for suite in $__Suites; do echo -n \"--suite $suite \"; done) \\\n            $__UbuntuPackages\n\n        exit 0\n    fi\n\n    __UpdateOptions=\n    if [[ \"$__SkipSigCheck\" == \"0\" ]]; then\n        __Keyring=\"$__Keyring --force-check-gpg\"\n    else\n        __Keyring=\n        __UpdateOptions=\"--allow-unauthenticated --allow-insecure-repositories\"\n    fi\n\n    # shellcheck disable=SC2086\n    echo running debootstrap \"--variant=minbase\" $__Keyring --arch \"$__UbuntuArch\" \"$__CodeName\" \"$__RootfsDir\" \"$__UbuntuRepo\"\n\n    # shellcheck disable=SC2086\n    if ! debootstrap \"--variant=minbase\" $__Keyring --arch \"$__UbuntuArch\" \"$__CodeName\" \"$__RootfsDir\" \"$__UbuntuRepo\"; then\n        echo \"debootstrap failed! dumping debootstrap.log\"\n        cat \"$__RootfsDir/debootstrap/debootstrap.log\"\n        exit 1\n    fi\n\n    rm -rf \"$__RootfsDir\"/etc/apt/*.{sources,list} \"$__RootfsDir\"/etc/apt/sources.list.d\n    mkdir -p \"$__RootfsDir/etc/apt/sources.list.d/\"\n\n    # shellcheck disable=SC2086\n    cat > \"$__RootfsDir/etc/apt/sources.list.d/$__CodeName.sources\" <<EOF\nTypes: deb\nURIs: $__UbuntuRepo\nSuites: $__Suites\nComponents: main universe\nSigned-By: $__KeyringFile\nEOF\n\n    # shellcheck disable=SC2086\n    chroot \"$__RootfsDir\" apt-get update $__UpdateOptions\n    chroot \"$__RootfsDir\" apt-get -f -y install\n    # shellcheck disable=SC2086\n    chroot \"$__RootfsDir\" apt-get -y install $__UbuntuPackages\n    chroot \"$__RootfsDir\" symlinks -cr /usr\n    chroot \"$__RootfsDir\" apt-get clean\n\n    if [[ \"$__SkipUnmount\" == \"0\" ]]; then\n        umount \"$__RootfsDir\"/* || true\n    fi\nelif [[ \"$__Tizen\" == \"tizen\" ]]; then\n    ROOTFS_DIR=\"$__RootfsDir\" \"$__CrossDir/tizen-build-rootfs.sh\" \"$__BuildArch\"\nelse\n    echo \"Unsupported target platform.\"\n    usage\nfi\n"
  },
  {
    "path": "eng/common/cross/install-debs.py",
    "content": "#!/usr/bin/env python3\n\nimport argparse\nimport asyncio\nimport aiohttp\nimport gzip\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\nimport tarfile\nimport tempfile\nimport zstandard\n\nfrom collections import deque\nfrom functools import cmp_to_key\n\nasync def download_file(session, url, dest_path, max_retries=3, retry_delay=2, timeout=60):\n    \"\"\"Asynchronous file download with retries.\"\"\"\n    attempt = 0\n    while attempt < max_retries:\n        try:\n            async with session.get(url, timeout=aiohttp.ClientTimeout(total=timeout)) as response:\n                if response.status == 200:\n                    with open(dest_path, \"wb\") as f:\n                        content = await response.read()\n                        f.write(content)\n                    print(f\"Downloaded {url} at {dest_path}\")\n                    return\n                else:\n                    print(f\"Failed to download {url}, Status Code: {response.status}\")\n                    break\n        except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e:\n            print(f\"Error downloading {url}: {type(e).__name__} - {e}. Retrying...\")\n\n        attempt += 1\n        await asyncio.sleep(retry_delay)\n\n    print(f\"Failed to download {url} after {max_retries} attempts.\")\n\nasync def download_deb_files_parallel(mirror, packages, tmp_dir):\n    \"\"\"Download .deb files in parallel.\"\"\"\n    os.makedirs(tmp_dir, exist_ok=True)\n\n    tasks = []\n    timeout = aiohttp.ClientTimeout(total=60)\n    async with aiohttp.ClientSession(timeout=timeout) as session:\n        for pkg, info in packages.items():\n            filename = info.get(\"Filename\")\n            if filename:\n                url = f\"{mirror}/{filename}\"\n                dest_path = os.path.join(tmp_dir, os.path.basename(filename))\n                tasks.append(asyncio.create_task(download_file(session, url, dest_path)))\n\n        await asyncio.gather(*tasks)\n\nasync def download_package_index_parallel(mirror, arch, suites):\n    \"\"\"Download package index files for specified suites and components entirely in memory.\"\"\"\n    tasks = []\n    timeout = aiohttp.ClientTimeout(total=60)\n\n    async with aiohttp.ClientSession(timeout=timeout) as session:\n        for suite in suites:\n            for component in [\"main\", \"universe\"]:\n                url = f\"{mirror}/dists/{suite}/{component}/binary-{arch}/Packages.gz\"\n                tasks.append(fetch_and_decompress(session, url))\n\n        results = await asyncio.gather(*tasks, return_exceptions=True)\n\n    merged_content = \"\"\n    for result in results:\n        if isinstance(result, str):\n            if merged_content:\n                merged_content += \"\\n\\n\"\n            merged_content += result\n\n    return merged_content\n\nasync def fetch_and_decompress(session, url):\n    \"\"\"Fetch and decompress the Packages.gz file.\"\"\"\n    try:\n        async with session.get(url) as response:\n            if response.status == 200:\n                compressed_data = await response.read()\n                decompressed_data = gzip.decompress(compressed_data).decode('utf-8')\n                print(f\"Downloaded index: {url}\")\n                return decompressed_data\n            else:\n                print(f\"Skipped index: {url} (doesn't exist)\")\n                return None\n    except Exception as e:\n        print(f\"Error fetching {url}: {e}\")\n\ndef parse_debian_version(version):\n    \"\"\"Parse a Debian package version into epoch, upstream version, and revision.\"\"\"\n    match = re.match(r'^(?:(\\d+):)?([^-]+)(?:-(.+))?$', version)\n    if not match:\n        raise ValueError(f\"Invalid Debian version format: {version}\")\n    epoch, upstream, revision = match.groups()\n    return int(epoch) if epoch else 0, upstream, revision or \"\"\n\ndef compare_upstream_version(v1, v2):\n    \"\"\"Compare upstream or revision parts using Debian rules.\"\"\"\n    def tokenize(version):\n        tokens = re.split(r'([0-9]+|[A-Za-z]+)', version)\n        return [int(x) if x.isdigit() else x for x in tokens if x]\n\n    tokens1 = tokenize(v1)\n    tokens2 = tokenize(v2)\n\n    for token1, token2 in zip(tokens1, tokens2):\n        if type(token1) == type(token2):\n            if token1 != token2:\n                return (token1 > token2) - (token1 < token2)\n        else:\n            return -1 if isinstance(token1, str) else 1\n\n    return len(tokens1) - len(tokens2)\n\ndef compare_debian_versions(version1, version2):\n    \"\"\"Compare two Debian package versions.\"\"\"\n    epoch1, upstream1, revision1 = parse_debian_version(version1)\n    epoch2, upstream2, revision2 = parse_debian_version(version2)\n\n    if epoch1 != epoch2:\n        return epoch1 - epoch2\n\n    result = compare_upstream_version(upstream1, upstream2)\n    if result != 0:\n        return result\n\n    return compare_upstream_version(revision1, revision2)\n\ndef resolve_dependencies(packages, aliases, desired_packages):\n    \"\"\"Recursively resolves dependencies for the desired packages.\"\"\"\n    resolved = []\n    to_process = deque(desired_packages)\n\n    while to_process:\n        current = to_process.popleft()\n        resolved_package = current if current in packages else aliases.get(current, [None])[0]\n\n        if not resolved_package:\n            print(f\"Error: Package '{current}' was not found in the available packages.\")\n            sys.exit(1)\n\n        if resolved_package not in resolved:\n            resolved.append(resolved_package)\n\n            deps = packages.get(resolved_package, {}).get(\"Depends\", \"\")\n            if deps:\n                deps = [dep.split(' ')[0] for dep in deps.split(', ') if dep]\n                for dep in deps:\n                    if dep not in resolved and dep not in to_process and dep in packages:\n                        to_process.append(dep)\n\n    return resolved\n\ndef parse_package_index(content):\n    \"\"\"Parses the Packages.gz file and returns package information.\"\"\"\n    packages = {}\n    aliases = {}\n    entries = re.split(r'\\n\\n+', content)\n\n    for entry in entries:\n        fields = dict(re.findall(r'^(\\S+): (.+)$', entry, re.MULTILINE))\n        if \"Package\" in fields:\n            package_name = fields[\"Package\"]\n            version = fields.get(\"Version\")\n            filename = fields.get(\"Filename\")\n            depends = fields.get(\"Depends\")\n            provides = fields.get(\"Provides\", None)\n\n            # Only update if package_name is not in packages or if the new version is higher\n            if package_name not in packages or compare_debian_versions(version, packages[package_name][\"Version\"]) > 0:\n                packages[package_name] = {\n                    \"Version\": version,\n                    \"Filename\": filename,\n                    \"Depends\": depends\n                }\n\n                # Update aliases if package provides any alternatives\n                if provides:\n                    provides_list = [x.strip() for x in provides.split(\",\")]\n                    for alias in provides_list:\n                        # Strip version specifiers\n                        alias_name = re.sub(r'\\s*\\(=.*\\)', '', alias)\n                        if alias_name not in aliases:\n                            aliases[alias_name] = []\n                        if package_name not in aliases[alias_name]:\n                            aliases[alias_name].append(package_name)\n\n    return packages, aliases\n\ndef install_packages(mirror, packages_info, aliases, tmp_dir, extract_dir, ar_tool, desired_packages):\n    \"\"\"Downloads .deb files and extracts them.\"\"\"\n    resolved_packages = resolve_dependencies(packages_info, aliases, desired_packages)\n    print(f\"Resolved packages (including dependencies): {resolved_packages}\")\n\n    packages_to_download = {}\n\n    for pkg in resolved_packages:\n        if pkg in packages_info:\n            packages_to_download[pkg] = packages_info[pkg]\n\n        if pkg in aliases:\n            for alias in aliases[pkg]:\n                if alias in packages_info:\n                    packages_to_download[alias] = packages_info[alias]\n\n    asyncio.run(download_deb_files_parallel(mirror, packages_to_download, tmp_dir))\n\n    package_to_deb_file_map = {}\n    for pkg in resolved_packages:\n        pkg_info = packages_info.get(pkg)\n        if pkg_info:\n            deb_filename = pkg_info.get(\"Filename\")\n            if deb_filename:\n                deb_file_path = os.path.join(tmp_dir, os.path.basename(deb_filename))\n                package_to_deb_file_map[pkg] = deb_file_path\n\n    for pkg in reversed(resolved_packages):\n        deb_file = package_to_deb_file_map.get(pkg)\n        if deb_file and os.path.exists(deb_file):\n            extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool)\n\n    print(\"All done!\")\n\ndef extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool):\n    \"\"\"Extract .deb file contents\"\"\"\n\n    os.makedirs(extract_dir, exist_ok=True)\n\n    with tempfile.TemporaryDirectory(dir=tmp_dir) as tmp_subdir:\n        result = subprocess.run(f\"{ar_tool} t {os.path.abspath(deb_file)}\", cwd=tmp_subdir, check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n\n        tar_filename = None\n        for line in result.stdout.decode().splitlines():\n            if line.startswith(\"data.tar\"):\n                tar_filename = line.strip()\n                break\n\n        if not tar_filename:\n            raise FileNotFoundError(f\"Could not find 'data.tar.*' in {deb_file}.\")\n\n        tar_file_path = os.path.join(tmp_subdir, tar_filename)\n        print(f\"Extracting {tar_filename} from {deb_file}..\")\n\n        subprocess.run(f\"{ar_tool} p {os.path.abspath(deb_file)} {tar_filename} > {tar_file_path}\", check=True, shell=True)\n\n        file_extension = os.path.splitext(tar_file_path)[1].lower()\n\n        if file_extension == \".xz\":\n            mode = \"r:xz\"\n        elif file_extension == \".gz\":\n            mode = \"r:gz\"\n        elif file_extension == \".zst\":\n            # zstd is not supported by standard library yet\n            decompressed_tar_path = tar_file_path.replace(\".zst\", \"\")\n            with open(tar_file_path, \"rb\") as zst_file, open(decompressed_tar_path, \"wb\") as decompressed_file:\n                dctx = zstandard.ZstdDecompressor()\n                dctx.copy_stream(zst_file, decompressed_file)\n\n            tar_file_path = decompressed_tar_path\n            mode = \"r\"\n        else:\n            raise ValueError(f\"Unsupported compression format: {file_extension}\")\n\n        with tarfile.open(tar_file_path, mode) as tar:\n            tar.extractall(path=extract_dir, filter='fully_trusted')\n\ndef finalize_setup(rootfsdir):\n    lib_dir = os.path.join(rootfsdir, 'lib')\n    usr_lib_dir = os.path.join(rootfsdir, 'usr', 'lib')\n\n    if os.path.exists(lib_dir):\n        if os.path.islink(lib_dir):\n            os.remove(lib_dir)\n        else:\n            os.makedirs(usr_lib_dir, exist_ok=True)\n\n            for item in os.listdir(lib_dir):\n                src = os.path.join(lib_dir, item)\n                dest = os.path.join(usr_lib_dir, item)\n\n                if os.path.isdir(src):\n                    shutil.copytree(src, dest, dirs_exist_ok=True)\n                else:\n                    shutil.copy2(src, dest)\n\n            shutil.rmtree(lib_dir)\n\n    os.symlink(usr_lib_dir, lib_dir)\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description=\"Generate rootfs for .NET runtime on Debian-like OS\")\n    parser.add_argument(\"--distro\", required=False, help=\"Distro name (e.g., debian, ubuntu, etc.)\")\n    parser.add_argument(\"--arch\", required=True, help=\"Architecture (e.g., amd64, loong64, etc.)\")\n    parser.add_argument(\"--rootfsdir\", required=True, help=\"Destination directory.\")\n    parser.add_argument('--suite', required=True, action='append', help='Specify one or more repository suites to collect index data.')\n    parser.add_argument(\"--mirror\", required=False, help=\"Mirror (e.g., http://ftp.debian.org/debian-ports etc.)\")\n    parser.add_argument(\"--artool\", required=False, default=\"ar\", help=\"ar tool to extract debs (e.g., ar, llvm-ar etc.)\")\n    parser.add_argument(\"packages\", nargs=\"+\", help=\"List of package names to be installed.\")\n\n    args = parser.parse_args()\n\n    if args.mirror is None:\n        if args.distro == \"ubuntu\":\n            args.mirror = \"http://archive.ubuntu.com/ubuntu\" if args.arch in [\"amd64\", \"i386\"] else \"http://ports.ubuntu.com/ubuntu-ports\"\n        elif args.distro == \"debian\":\n            args.mirror = \"http://ftp.debian.org/debian-ports\"\n        else:\n            raise Exception(\"Unsupported distro\")\n\n    DESIRED_PACKAGES = args.packages + [ # base packages\n        \"dpkg\",\n        \"busybox\",\n        \"libc-bin\",\n        \"base-files\",\n        \"base-passwd\",\n        \"debianutils\"\n    ]\n\n    print(f\"Creating rootfs. rootfsdir: {args.rootfsdir}, distro: {args.distro}, arch: {args.arch}, suites: {args.suite}, mirror: {args.mirror}\")\n\n    package_index_content = asyncio.run(download_package_index_parallel(args.mirror, args.arch, args.suite))\n\n    packages_info, aliases = parse_package_index(package_index_content)\n\n    with tempfile.TemporaryDirectory() as tmp_dir:\n        install_packages(args.mirror, packages_info, aliases, tmp_dir, args.rootfsdir, args.artool, DESIRED_PACKAGES)\n\n    finalize_setup(args.rootfsdir)\n"
  },
  {
    "path": "eng/common/cross/riscv64/tizen/tizen.patch",
    "content": "diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so\n--- a/usr/lib64/libc.so\t2016-12-30 23:00:08.284951863 +0900\n+++ b/usr/lib64/libc.so\t2016-12-30 23:00:32.140951815 +0900\n@@ -2,4 +2,4 @@\n    Use the shared library, but some functions are only in\n    the static library, so try that secondarily.  */\n OUTPUT_FORMAT(elf64-littleriscv)\n-GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /lib64/ld-linux-riscv64-lp64d.so.1 ) )\n+GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-riscv64-lp64d.so.1 ) )\n"
  },
  {
    "path": "eng/common/cross/tizen-build-rootfs.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nARCH=$1\nLINK_ARCH=$ARCH\n\ncase \"$ARCH\" in\n    arm)\n        TIZEN_ARCH=\"armv7hl\"\n        ;;\n    armel)\n        TIZEN_ARCH=\"armv7l\"\n        LINK_ARCH=\"arm\"\n        ;;\n    arm64)\n        TIZEN_ARCH=\"aarch64\"\n        ;;\n    x86)\n        TIZEN_ARCH=\"i686\"\n        ;;\n    x64)\n        TIZEN_ARCH=\"x86_64\"\n        LINK_ARCH=\"x86\"\n        ;;\n    riscv64)\n        TIZEN_ARCH=\"riscv64\"\n        LINK_ARCH=\"riscv\"\n        ;;\n    *)\n        echo \"Unsupported architecture for tizen: $ARCH\"\n        exit 1\nesac\n\n__CrossDir=$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\n__TIZEN_CROSSDIR=\"$__CrossDir/${ARCH}/tizen\"\n\nif [[ -z \"$ROOTFS_DIR\" ]]; then\n    echo \"ROOTFS_DIR is not defined.\"\n    exit 1;\nfi\n\nTIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp\nmkdir -p $TIZEN_TMP_DIR\n\n# Download files\necho \">>Start downloading files\"\nVERBOSE=1 $__CrossDir/tizen-fetch.sh $TIZEN_TMP_DIR $TIZEN_ARCH\necho \"<<Finish downloading files\"\n\necho \">>Start constructing Tizen rootfs\"\nTIZEN_RPM_FILES=`ls $TIZEN_TMP_DIR/*.rpm`\ncd $ROOTFS_DIR\nfor f in $TIZEN_RPM_FILES; do\n    rpm2cpio $f  | cpio -idm --quiet\ndone\necho \"<<Finish constructing Tizen rootfs\"\n\n# Cleanup tmp\nrm -rf $TIZEN_TMP_DIR\n\n# Configure Tizen rootfs\necho \">>Start configuring Tizen rootfs\"\nln -sfn asm-${LINK_ARCH} ./usr/include/asm\npatch -p1 < $__TIZEN_CROSSDIR/tizen.patch\nif [[ \"$TIZEN_ARCH\" == \"riscv64\" ]]; then\n    echo \"Fixing broken symlinks in $PWD\"\n    rm ./usr/lib64/libresolv.so\n    ln -s ../../lib64/libresolv.so.2 ./usr/lib64/libresolv.so\n    rm ./usr/lib64/libpthread.so\n    ln -s ../../lib64/libpthread.so.0 ./usr/lib64/libpthread.so\n    rm ./usr/lib64/libdl.so\n    ln -s ../../lib64/libdl.so.2 ./usr/lib64/libdl.so\n    rm ./usr/lib64/libutil.so\n    ln -s ../../lib64/libutil.so.1 ./usr/lib64/libutil.so\n    rm ./usr/lib64/libm.so\n    ln -s ../../lib64/libm.so.6 ./usr/lib64/libm.so\n    rm ./usr/lib64/librt.so\n    ln -s ../../lib64/librt.so.1 ./usr/lib64/librt.so\n    rm ./lib/ld-linux-riscv64-lp64d.so.1\n    ln -s ../lib64/ld-linux-riscv64-lp64d.so.1 ./lib/ld-linux-riscv64-lp64d.so.1\nfi\necho \"<<Finish configuring Tizen rootfs\"\n"
  },
  {
    "path": "eng/common/cross/tizen-fetch.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nif [[ -z \"${VERBOSE// }\" ]] || [ \"$VERBOSE\" -ne \"$VERBOSE\" ] 2>/dev/null; then\n    VERBOSE=0\nfi\n\nLog()\n{\n    if [ $VERBOSE -ge 1 ]; then\n        echo ${@:2}\n    fi\n}\n\nInform()\n{\n    Log 1 -e \"\\x1B[0;34m$@\\x1B[m\"\n}\n\nDebug()\n{\n    Log 2 -e \"\\x1B[0;32m$@\\x1B[m\"\n}\n\nError()\n{\n    >&2 Log 0 -e \"\\x1B[0;31m$@\\x1B[m\"\n}\n\nFetch()\n{\n    URL=$1\n    FILE=$2\n    PROGRESS=$3\n    if [ $VERBOSE -ge 1 ] && [ $PROGRESS ]; then\n        CURL_OPT=\"--progress-bar\"\n    else\n        CURL_OPT=\"--silent\"\n    fi\n    curl $CURL_OPT $URL > $FILE\n}\n\nhash curl 2> /dev/null || { Error \"Require 'curl' Aborting.\"; exit 1; }\nhash xmllint 2> /dev/null || { Error \"Require 'xmllint' Aborting.\"; exit 1; }\nhash sha256sum 2> /dev/null || { Error \"Require 'sha256sum' Aborting.\"; exit 1; }\n\nTMPDIR=$1\nif [ ! -d $TMPDIR ]; then\n    TMPDIR=./tizen_tmp\n    Debug \"Create temporary directory : $TMPDIR\"\n    mkdir -p $TMPDIR\nfi\n\nTIZEN_ARCH=$2\n\nTIZEN_URL=http://download.tizen.org/snapshots/TIZEN/Tizen\nBUILD_XML=build.xml\nREPOMD_XML=repomd.xml\nPRIMARY_XML=primary.xml\nTARGET_URL=\"http://__not_initialized\"\n\nXpath_get()\n{\n    XPATH_RESULT=''\n    XPATH=$1\n    XML_FILE=$2\n    RESULT=$(xmllint --xpath $XPATH $XML_FILE)\n    if [[ -z ${RESULT// } ]]; then\n        Error \"Can not find target from $XML_FILE\"\n        Debug \"Xpath = $XPATH\"\n        exit 1\n    fi\n    XPATH_RESULT=$RESULT\n}\n\nfetch_tizen_pkgs_init()\n{\n    TARGET=$1\n    PROFILE=$2\n    Debug \"Initialize TARGET=$TARGET, PROFILE=$PROFILE\"\n\n    TMP_PKG_DIR=$TMPDIR/tizen_${PROFILE}_pkgs\n    if [ -d $TMP_PKG_DIR ]; then rm -rf $TMP_PKG_DIR; fi\n    mkdir -p $TMP_PKG_DIR\n\n    PKG_URL=$TIZEN_URL/$PROFILE/latest\n\n    BUILD_XML_URL=$PKG_URL/$BUILD_XML\n    TMP_BUILD=$TMP_PKG_DIR/$BUILD_XML\n    TMP_REPOMD=$TMP_PKG_DIR/$REPOMD_XML\n    TMP_PRIMARY=$TMP_PKG_DIR/$PRIMARY_XML\n    TMP_PRIMARYGZ=${TMP_PRIMARY}.gz\n\n    Fetch $BUILD_XML_URL $TMP_BUILD\n\n    Debug \"fetch $BUILD_XML_URL to $TMP_BUILD\"\n\n    TARGET_XPATH=\"//build/buildtargets/buildtarget[@name=\\\"$TARGET\\\"]/repo[@type=\\\"binary\\\"]/text()\"\n    Xpath_get $TARGET_XPATH $TMP_BUILD\n    TARGET_PATH=$XPATH_RESULT\n    TARGET_URL=$PKG_URL/$TARGET_PATH\n\n    REPOMD_URL=$TARGET_URL/repodata/repomd.xml\n    PRIMARY_XPATH='string(//*[local-name()=\"data\"][@type=\"primary\"]/*[local-name()=\"location\"]/@href)'\n\n    Fetch $REPOMD_URL $TMP_REPOMD\n\n    Debug \"fetch $REPOMD_URL to $TMP_REPOMD\"\n\n    Xpath_get $PRIMARY_XPATH $TMP_REPOMD\n    PRIMARY_XML_PATH=$XPATH_RESULT\n    PRIMARY_URL=$TARGET_URL/$PRIMARY_XML_PATH\n\n    Fetch $PRIMARY_URL $TMP_PRIMARYGZ\n\n    Debug \"fetch $PRIMARY_URL to $TMP_PRIMARYGZ\"\n\n    gunzip $TMP_PRIMARYGZ\n\n    Debug \"unzip $TMP_PRIMARYGZ to $TMP_PRIMARY\"\n}\n\nfetch_tizen_pkgs()\n{\n    ARCH=$1\n    PACKAGE_XPATH_TPL='string(//*[local-name()=\"metadata\"]/*[local-name()=\"package\"][*[local-name()=\"name\"][text()=\"_PKG_\"]][*[local-name()=\"arch\"][text()=\"_ARCH_\"]]/*[local-name()=\"location\"]/@href)'\n\n    PACKAGE_CHECKSUM_XPATH_TPL='string(//*[local-name()=\"metadata\"]/*[local-name()=\"package\"][*[local-name()=\"name\"][text()=\"_PKG_\"]][*[local-name()=\"arch\"][text()=\"_ARCH_\"]]/*[local-name()=\"checksum\"]/text())'\n\n    for pkg in ${@:2}\n    do\n        Inform \"Fetching... $pkg\"\n        XPATH=${PACKAGE_XPATH_TPL/_PKG_/$pkg}\n        XPATH=${XPATH/_ARCH_/$ARCH}\n        Xpath_get $XPATH $TMP_PRIMARY\n        PKG_PATH=$XPATH_RESULT\n\n        XPATH=${PACKAGE_CHECKSUM_XPATH_TPL/_PKG_/$pkg}\n        XPATH=${XPATH/_ARCH_/$ARCH}\n        Xpath_get $XPATH $TMP_PRIMARY\n        CHECKSUM=$XPATH_RESULT\n\n        PKG_URL=$TARGET_URL/$PKG_PATH\n        PKG_FILE=$(basename $PKG_PATH)\n        PKG_PATH=$TMPDIR/$PKG_FILE\n\n        Debug \"Download $PKG_URL to $PKG_PATH\"\n        Fetch $PKG_URL $PKG_PATH true\n\n        echo \"$CHECKSUM $PKG_PATH\" | sha256sum -c - > /dev/null\n        if [ $? -ne 0 ]; then\n            Error \"Fail to fetch $PKG_URL to $PKG_PATH\"\n            Debug \"Checksum = $CHECKSUM\"\n            exit 1\n        fi\n    done\n}\n\nBASE=\"Tizen-Base\"\nUNIFIED=\"Tizen-Unified\"\n\nInform \"Initialize ${TIZEN_ARCH} base\"\nfetch_tizen_pkgs_init standard $BASE\nInform \"fetch common packages\"\nfetch_tizen_pkgs ${TIZEN_ARCH} gcc gcc-devel-static glibc glibc-devel libicu libicu-devel libatomic linux-glibc-devel keyutils keyutils-devel libkeyutils\nInform \"fetch coreclr packages\"\nfetch_tizen_pkgs ${TIZEN_ARCH} libgcc libstdc++ libstdc++-devel libunwind libunwind-devel lttng-ust-devel lttng-ust userspace-rcu-devel userspace-rcu\nif [ \"$TIZEN_ARCH\" != \"riscv64\" ]; then\n    fetch_tizen_pkgs ${TIZEN_ARCH} lldb lldb-devel\nfi\nInform \"fetch corefx packages\"\nfetch_tizen_pkgs ${TIZEN_ARCH} libcom_err libcom_err-devel zlib zlib-devel libopenssl11 libopenssl1.1-devel krb5 krb5-devel\n\nInform \"Initialize standard unified\"\nfetch_tizen_pkgs_init standard $UNIFIED\nInform \"fetch corefx packages\"\nfetch_tizen_pkgs ${TIZEN_ARCH} gssdp gssdp-devel tizen-release\n\n"
  },
  {
    "path": "eng/common/cross/toolchain.cmake",
    "content": "set(CROSS_ROOTFS $ENV{ROOTFS_DIR})\n\n# reset platform variables (e.g. cmake 3.25 sets LINUX=1)\nunset(LINUX)\nunset(FREEBSD)\nunset(ILLUMOS)\nunset(ANDROID)\nunset(TIZEN)\nunset(HAIKU)\n\nset(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH})\nif(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version)\n  set(CMAKE_SYSTEM_NAME FreeBSD)\n  set(FREEBSD 1)\nelseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc)\n  set(CMAKE_SYSTEM_NAME SunOS)\n  set(ILLUMOS 1)\nelseif(EXISTS ${CROSS_ROOTFS}/boot/system/develop/headers/config/HaikuConfig.h)\n  set(CMAKE_SYSTEM_NAME Haiku)\n  set(HAIKU 1)\nelse()\n  set(CMAKE_SYSTEM_NAME Linux)\n  set(LINUX 1)\nendif()\nset(CMAKE_SYSTEM_VERSION 1)\n\nif(EXISTS ${CROSS_ROOTFS}/etc/tizen-release)\n  set(TIZEN 1)\nelseif(EXISTS ${CROSS_ROOTFS}/android_platform)\n  set(ANDROID 1)\nendif()\n\nif(TARGET_ARCH_NAME STREQUAL \"arm\")\n  set(CMAKE_SYSTEM_PROCESSOR armv7l)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf)\n    set(TOOLCHAIN \"armv7-alpine-linux-musleabihf\")\n  elseif(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)\n    set(TOOLCHAIN \"armv6-alpine-linux-musleabihf\")\n  else()\n    set(TOOLCHAIN \"arm-linux-gnueabihf\")\n  endif()\n  if(TIZEN)\n    set(TIZEN_TOOLCHAIN \"armv7hl-tizen-linux-gnueabihf\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"arm64\")\n  set(CMAKE_SYSTEM_PROCESSOR aarch64)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl)\n    set(TOOLCHAIN \"aarch64-alpine-linux-musl\")\n  elseif(LINUX)\n    set(TOOLCHAIN \"aarch64-linux-gnu\")\n    if(TIZEN)\n      set(TIZEN_TOOLCHAIN \"aarch64-tizen-linux-gnu\")\n    endif()\n  elseif(FREEBSD)\n    set(triple \"aarch64-unknown-freebsd12\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"armel\")\n  set(CMAKE_SYSTEM_PROCESSOR armv7l)\n  set(TOOLCHAIN \"arm-linux-gnueabi\")\n  if(TIZEN)\n    set(TIZEN_TOOLCHAIN \"armv7l-tizen-linux-gnueabi\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"armv6\")\n  set(CMAKE_SYSTEM_PROCESSOR armv6l)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)\n    set(TOOLCHAIN \"armv6-alpine-linux-musleabihf\")\n  else()\n    set(TOOLCHAIN \"arm-linux-gnueabihf\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"loongarch64\")\n  set(CMAKE_SYSTEM_PROCESSOR \"loongarch64\")\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/loongarch64-alpine-linux-musl)\n    set(TOOLCHAIN \"loongarch64-alpine-linux-musl\")\n  else()\n    set(TOOLCHAIN \"loongarch64-linux-gnu\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"ppc64le\")\n  set(CMAKE_SYSTEM_PROCESSOR ppc64le)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/powerpc64le-alpine-linux-musl)\n    set(TOOLCHAIN \"powerpc64le-alpine-linux-musl\")\n  else()\n    set(TOOLCHAIN \"powerpc64le-linux-gnu\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"riscv64\")\n  set(CMAKE_SYSTEM_PROCESSOR riscv64)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/riscv64-alpine-linux-musl)\n    set(TOOLCHAIN \"riscv64-alpine-linux-musl\")\n  else()\n    set(TOOLCHAIN \"riscv64-linux-gnu\")\n    if(TIZEN)\n      set(TIZEN_TOOLCHAIN \"riscv64-tizen-linux-gnu\")\n    endif()\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"s390x\")\n  set(CMAKE_SYSTEM_PROCESSOR s390x)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/s390x-alpine-linux-musl)\n    set(TOOLCHAIN \"s390x-alpine-linux-musl\")\n  else()\n    set(TOOLCHAIN \"s390x-linux-gnu\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"x64\")\n  set(CMAKE_SYSTEM_PROCESSOR x86_64)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl)\n    set(TOOLCHAIN \"x86_64-alpine-linux-musl\")\n  elseif(LINUX)\n    set(TOOLCHAIN \"x86_64-linux-gnu\")\n    if(TIZEN)\n      set(TIZEN_TOOLCHAIN \"x86_64-tizen-linux-gnu\")\n    endif()\n  elseif(FREEBSD)\n    set(triple \"x86_64-unknown-freebsd12\")\n  elseif(ILLUMOS)\n    set(TOOLCHAIN \"x86_64-illumos\")\n  elseif(HAIKU)\n    set(TOOLCHAIN \"x86_64-unknown-haiku\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"x86\")\n  set(CMAKE_SYSTEM_PROCESSOR i686)\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl)\n    set(TOOLCHAIN \"i586-alpine-linux-musl\")\n  else()\n    set(TOOLCHAIN \"i686-linux-gnu\")\n  endif()\n  if(TIZEN)\n    set(TIZEN_TOOLCHAIN \"i586-tizen-linux-gnu\")\n  endif()\nelse()\n  message(FATAL_ERROR \"Arch is ${TARGET_ARCH_NAME}. Only arm, arm64, armel, armv6, loongarch64, ppc64le, riscv64, s390x, x64 and x86 are supported!\")\nendif()\n\nif(DEFINED ENV{TOOLCHAIN})\n  set(TOOLCHAIN $ENV{TOOLCHAIN})\nendif()\n\n# Specify include paths\nif(TIZEN)\n  function(find_toolchain_dir prefix)\n    # Dynamically find the version subdirectory\n    file(GLOB DIRECTORIES \"${prefix}/*\")\n    list(GET DIRECTORIES 0 FIRST_MATCH)\n    get_filename_component(TOOLCHAIN_VERSION ${FIRST_MATCH} NAME)\n\n    set(TIZEN_TOOLCHAIN_PATH \"${prefix}/${TOOLCHAIN_VERSION}\" PARENT_SCOPE)\n  endfunction()\n\n  if(TARGET_ARCH_NAME MATCHES \"^(arm|armel|x86)$\")\n    find_toolchain_dir(\"${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}\")\n  else()\n    find_toolchain_dir(\"${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}\")\n  endif()\n\n  message(STATUS \"TIZEN_TOOLCHAIN_PATH set to: ${TIZEN_TOOLCHAIN_PATH}\")\n\n  include_directories(SYSTEM ${TIZEN_TOOLCHAIN_PATH}/include/c++)\n  include_directories(SYSTEM ${TIZEN_TOOLCHAIN_PATH}/include/c++/${TIZEN_TOOLCHAIN})\nendif()\n\nfunction(locate_toolchain_exec exec var)\n    set(TOOLSET_PREFIX ${TOOLCHAIN}-)\n    string(TOUPPER ${exec} EXEC_UPPERCASE)\n    if(NOT \"$ENV{CLR_${EXEC_UPPERCASE}}\" STREQUAL \"\")\n        set(${var} \"$ENV{CLR_${EXEC_UPPERCASE}}\" PARENT_SCOPE)\n        return()\n    endif()\n\n    find_program(EXEC_LOCATION_${exec}\n        NAMES\n        \"${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}\"\n        \"${TOOLSET_PREFIX}${exec}\")\n\n    if (EXEC_LOCATION_${exec} STREQUAL \"EXEC_LOCATION_${exec}-NOTFOUND\")\n        message(FATAL_ERROR \"Unable to find toolchain executable. Name: ${exec}, Prefix: ${TOOLSET_PREFIX}.\")\n    endif()\n    set(${var} ${EXEC_LOCATION_${exec}} PARENT_SCOPE)\nendfunction()\n\nif(ANDROID)\n    if(TARGET_ARCH_NAME STREQUAL \"arm\")\n        set(ANDROID_ABI armeabi-v7a)\n    elseif(TARGET_ARCH_NAME STREQUAL \"arm64\")\n        set(ANDROID_ABI arm64-v8a)\n    endif()\n\n    # extract platform number required by the NDK's toolchain\n    file(READ \"${CROSS_ROOTFS}/android_platform\" RID_FILE_CONTENTS)\n    string(REPLACE \"RID=\" \"\" ANDROID_RID \"${RID_FILE_CONTENTS}\")\n    string(REGEX REPLACE \".*\\\\.([0-9]+)-.*\" \"\\\\1\" ANDROID_PLATFORM \"${ANDROID_RID}\")\n\n    set(ANDROID_TOOLCHAIN clang)\n    set(FEATURE_EVENT_TRACE 0) # disable event trace as there is no lttng-ust package in termux repository\n    set(CMAKE_SYSTEM_LIBRARY_PATH \"${CROSS_ROOTFS}/usr/lib\")\n    set(CMAKE_SYSTEM_INCLUDE_PATH \"${CROSS_ROOTFS}/usr/include\")\n\n    # include official NDK toolchain script\n    include(${CROSS_ROOTFS}/../build/cmake/android.toolchain.cmake)\nelseif(FREEBSD)\n    # we cross-compile by instructing clang\n    set(CMAKE_C_COMPILER_TARGET ${triple})\n    set(CMAKE_CXX_COMPILER_TARGET ${triple})\n    set(CMAKE_ASM_COMPILER_TARGET ${triple})\n    set(CMAKE_SYSROOT \"${CROSS_ROOTFS}\")\n    set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld\")\n    set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld\")\n    set(CMAKE_MODULE_LINKER_FLAGS \"${CMAKE_MODULE_LINKER_FLAGS} -fuse-ld=lld\")\nelseif(ILLUMOS)\n    set(CMAKE_SYSROOT \"${CROSS_ROOTFS}\")\n    set(CMAKE_SYSTEM_PREFIX_PATH \"${CROSS_ROOTFS}\")\n    set(CMAKE_C_STANDARD_LIBRARIES \"${CMAKE_C_STANDARD_LIBRARIES} -lssp\")\n    set(CMAKE_CXX_STANDARD_LIBRARIES \"${CMAKE_CXX_STANDARD_LIBRARIES} -lssp\")\n\n    include_directories(SYSTEM ${CROSS_ROOTFS}/include)\n\n    locate_toolchain_exec(gcc CMAKE_C_COMPILER)\n    locate_toolchain_exec(g++ CMAKE_CXX_COMPILER)\nelseif(HAIKU)\n    set(CMAKE_SYSROOT \"${CROSS_ROOTFS}\")\n    set(CMAKE_PROGRAM_PATH \"${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin\")\n    set(CMAKE_SYSTEM_PREFIX_PATH \"${CROSS_ROOTFS}\")\n    set(CMAKE_C_STANDARD_LIBRARIES \"${CMAKE_C_STANDARD_LIBRARIES} -lssp\")\n    set(CMAKE_CXX_STANDARD_LIBRARIES \"${CMAKE_CXX_STANDARD_LIBRARIES} -lssp\")\n\n    locate_toolchain_exec(gcc CMAKE_C_COMPILER)\n    locate_toolchain_exec(g++ CMAKE_CXX_COMPILER)\n\n    # let CMake set up the correct search paths\n    include(Platform/Haiku)\nelse()\n    set(CMAKE_SYSROOT \"${CROSS_ROOTFS}\")\n\n    set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN \"${CROSS_ROOTFS}/usr\")\n    set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN \"${CROSS_ROOTFS}/usr\")\n    set(CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN \"${CROSS_ROOTFS}/usr\")\nendif()\n\n# Specify link flags\n\nfunction(add_toolchain_linker_flag Flag)\n  set(Config \"${ARGV1}\")\n  set(CONFIG_SUFFIX \"\")\n  if (NOT Config STREQUAL \"\")\n    set(CONFIG_SUFFIX \"_${Config}\")\n  endif()\n  set(\"CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}_INIT\" \"${CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}_INIT} ${Flag}\" PARENT_SCOPE)\n  set(\"CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}_INIT\" \"${CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}_INIT} ${Flag}\" PARENT_SCOPE)\nendfunction()\n\nif(LINUX)\n  add_toolchain_linker_flag(\"-Wl,--rpath-link=${CROSS_ROOTFS}/lib/${TOOLCHAIN}\")\n  add_toolchain_linker_flag(\"-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}\")\nendif()\n\nif(TARGET_ARCH_NAME MATCHES \"^(arm|armel)$\")\n  if(TIZEN)\n    add_toolchain_linker_flag(\"-B${TIZEN_TOOLCHAIN_PATH}\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/lib\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/usr/lib\")\n    add_toolchain_linker_flag(\"-L${TIZEN_TOOLCHAIN_PATH}\")\n  endif()\nelseif(TARGET_ARCH_NAME MATCHES \"^(arm64|x64|riscv64)$\")\n  if(TIZEN)\n    add_toolchain_linker_flag(\"-B${TIZEN_TOOLCHAIN_PATH}\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/lib64\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/usr/lib64\")\n    add_toolchain_linker_flag(\"-L${TIZEN_TOOLCHAIN_PATH}\")\n\n    add_toolchain_linker_flag(\"-Wl,--rpath-link=${CROSS_ROOTFS}/lib64\")\n    add_toolchain_linker_flag(\"-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64\")\n    add_toolchain_linker_flag(\"-Wl,--rpath-link=${TIZEN_TOOLCHAIN_PATH}\")\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"s390x\")\n  add_toolchain_linker_flag(\"--target=${TOOLCHAIN}\")\nelseif(TARGET_ARCH_NAME STREQUAL \"x86\")\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl)\n    add_toolchain_linker_flag(\"--target=${TOOLCHAIN}\")\n    add_toolchain_linker_flag(\"-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}\")\n  endif()\n  add_toolchain_linker_flag(-m32)\n  if(TIZEN)\n    add_toolchain_linker_flag(\"-B${TIZEN_TOOLCHAIN_PATH}\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/lib\")\n    add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/usr/lib\")\n    add_toolchain_linker_flag(\"-L${TIZEN_TOOLCHAIN_PATH}\")\n  endif()\nelseif(ILLUMOS)\n  add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/lib/amd64\")\n  add_toolchain_linker_flag(\"-L${CROSS_ROOTFS}/usr/amd64/lib\")\nelseif(HAIKU)\n  add_toolchain_linker_flag(\"-lnetwork\")\n  add_toolchain_linker_flag(\"-lroot\")\nendif()\n\n# Specify compile options\n\nif((TARGET_ARCH_NAME MATCHES \"^(arm|arm64|armel|armv6|loongarch64|ppc64le|riscv64|s390x|x64|x86)$\" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU)\n  set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN})\n  set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN})\n  set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN})\nendif()\n\nif(TARGET_ARCH_NAME MATCHES \"^(arm|armel)$\")\n  add_compile_options(-mthumb)\n  if (NOT DEFINED CLR_ARM_FPU_TYPE)\n    set (CLR_ARM_FPU_TYPE vfpv3)\n  endif (NOT DEFINED CLR_ARM_FPU_TYPE)\n\n  add_compile_options (-mfpu=${CLR_ARM_FPU_TYPE})\n  if (NOT DEFINED CLR_ARM_FPU_CAPABILITY)\n    set (CLR_ARM_FPU_CAPABILITY 0x7)\n  endif (NOT DEFINED CLR_ARM_FPU_CAPABILITY)\n\n  add_definitions (-DCLR_ARM_FPU_CAPABILITY=${CLR_ARM_FPU_CAPABILITY})\n\n  # persist variables across multiple try_compile passes\n  list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CLR_ARM_FPU_TYPE CLR_ARM_FPU_CAPABILITY)\n\n  if(TARGET_ARCH_NAME STREQUAL \"armel\")\n    add_compile_options(-mfloat-abi=softfp)\n  endif()\nelseif(TARGET_ARCH_NAME STREQUAL \"s390x\")\n  add_compile_options(\"--target=${TOOLCHAIN}\")\nelseif(TARGET_ARCH_NAME STREQUAL \"x86\")\n  if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl)\n    add_compile_options(--target=${TOOLCHAIN})\n  endif()\n  add_compile_options(-m32)\n  add_compile_options(-Wno-error=unused-command-line-argument)\nendif()\n\nif(TIZEN)\n  if(TARGET_ARCH_NAME MATCHES \"^(arm|armel|arm64|x86)$\")\n    add_compile_options(-Wno-deprecated-declarations) # compile-time option\n    add_compile_options(-D__extern_always_inline=inline) # compile-time option\n  endif()\nendif()\n\n# Set LLDB include and library paths for builds that need lldb.\nif(TARGET_ARCH_NAME MATCHES \"^(arm|armel|x86)$\")\n  if(TARGET_ARCH_NAME STREQUAL \"x86\")\n    set(LLVM_CROSS_DIR \"$ENV{LLVM_CROSS_HOME}\")\n  else() # arm/armel case\n    set(LLVM_CROSS_DIR \"$ENV{LLVM_ARM_HOME}\")\n  endif()\n  if(LLVM_CROSS_DIR)\n    set(WITH_LLDB_LIBS \"${LLVM_CROSS_DIR}/lib/\" CACHE STRING \"\")\n    set(WITH_LLDB_INCLUDES \"${LLVM_CROSS_DIR}/include\" CACHE STRING \"\")\n    set(LLDB_H \"${WITH_LLDB_INCLUDES}\" CACHE STRING \"\")\n    set(LLDB \"${LLVM_CROSS_DIR}/lib/liblldb.so\" CACHE STRING \"\")\n  else()\n    if(TARGET_ARCH_NAME STREQUAL \"x86\")\n      set(WITH_LLDB_LIBS \"${CROSS_ROOTFS}/usr/lib/i386-linux-gnu\" CACHE STRING \"\")\n      set(CHECK_LLVM_DIR \"${CROSS_ROOTFS}/usr/lib/llvm-3.8/include\")\n      if(EXISTS \"${CHECK_LLVM_DIR}\" AND IS_DIRECTORY \"${CHECK_LLVM_DIR}\")\n        set(WITH_LLDB_INCLUDES \"${CHECK_LLVM_DIR}\")\n      else()\n        set(WITH_LLDB_INCLUDES \"${CROSS_ROOTFS}/usr/lib/llvm-3.6/include\")\n      endif()\n    else() # arm/armel case\n      set(WITH_LLDB_LIBS \"${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}\" CACHE STRING \"\")\n      set(WITH_LLDB_INCLUDES \"${CROSS_ROOTFS}/usr/lib/llvm-3.6/include\" CACHE STRING \"\")\n    endif()\n  endif()\nendif()\n\n# Set C++ standard library options if specified\nset(CLR_CMAKE_CXX_STANDARD_LIBRARY \"\" CACHE STRING \"Standard library flavor to link against. Only supported with the Clang compiler.\")\nif (CLR_CMAKE_CXX_STANDARD_LIBRARY)\n  add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:--stdlib=${CLR_CMAKE_CXX_STANDARD_LIBRARY}>)\n  add_link_options($<$<LINK_LANG_AND_ID:CXX,Clang>:--stdlib=${CLR_CMAKE_CXX_STANDARD_LIBRARY}>)\nendif()\n\noption(CLR_CMAKE_CXX_STANDARD_LIBRARY_STATIC \"Statically link against the C++ standard library\" OFF)\nif(CLR_CMAKE_CXX_STANDARD_LIBRARY_STATIC)\n  add_link_options($<$<LINK_LANGUAGE:CXX>:-static-libstdc++>)\nendif()\n\nset(CLR_CMAKE_CXX_ABI_LIBRARY \"\" CACHE STRING \"C++ ABI implementation library to link against. Only supported with the Clang compiler.\")\nif (CLR_CMAKE_CXX_ABI_LIBRARY)\n  # The user may specify the ABI library with the 'lib' prefix, like 'libstdc++'. Strip the prefix here so the linker finds the right library.\n  string(REGEX REPLACE \"^lib(.+)\" \"\\\\1\" CLR_CMAKE_CXX_ABI_LIBRARY ${CLR_CMAKE_CXX_ABI_LIBRARY})\n  # We need to specify this as a linker-backend option as Clang will filter this option out when linking to libc++.\n  add_link_options(\"LINKER:-l${CLR_CMAKE_CXX_ABI_LIBRARY}\")\nendif()\n\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n"
  },
  {
    "path": "eng/common/darc-init.ps1",
    "content": "param (\n    $darcVersion = $null,\n    $versionEndpoint = 'https://maestro.dot.net/api/assets/darc-version?api-version=2020-02-20',\n    $verbosity = 'minimal',\n    $toolpath = $null\n)\n\n. $PSScriptRoot\\tools.ps1\n\nfunction InstallDarcCli ($darcVersion, $toolpath) {\n  $darcCliPackageName = 'microsoft.dotnet.darc'\n\n  $dotnetRoot = InitializeDotNetCli -install:$true\n  $dotnet = \"$dotnetRoot\\dotnet.exe\"\n  $toolList = & \"$dotnet\" tool list -g\n\n  if ($toolList -like \"*$darcCliPackageName*\") {\n    & \"$dotnet\" tool uninstall $darcCliPackageName -g\n  }\n\n  # If the user didn't explicitly specify the darc version,\n  # query the Maestro API for the correct version of darc to install.\n  if (-not $darcVersion) {\n    $darcVersion = $(Invoke-WebRequest -Uri $versionEndpoint -UseBasicParsing).Content\n  }\n\n  $arcadeServicesSource = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'\n\n  Write-Host \"Installing Darc CLI version $darcVersion...\"\n  Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'\n  if (-not $toolpath) {\n    Write-Host \"'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity -g\"\n    & \"$dotnet\" tool install $darcCliPackageName --version $darcVersion --add-source \"$arcadeServicesSource\" -v $verbosity -g\n  }else {\n    Write-Host \"'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity --tool-path '$toolpath'\"\n    & \"$dotnet\" tool install $darcCliPackageName --version $darcVersion --add-source \"$arcadeServicesSource\" -v $verbosity --tool-path \"$toolpath\"\n  }\n}\n\ntry {\n  InstallDarcCli $darcVersion $toolpath\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'Darc' -Message $_\n  ExitWithExitCode 1\n}"
  },
  {
    "path": "eng/common/darc-init.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\ndarcVersion=''\nversionEndpoint='https://maestro.dot.net/api/assets/darc-version?api-version=2020-02-20'\nverbosity='minimal'\n\nwhile [[ $# > 0 ]]; do\n  opt=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n  case \"$opt\" in\n    --darcversion)\n      darcVersion=$2\n      shift\n      ;;\n    --versionendpoint)\n      versionEndpoint=$2\n      shift\n      ;;\n    --verbosity)\n      verbosity=$2\n      shift\n      ;;\n    --toolpath)\n      toolpath=$2\n      shift\n      ;;\n    *)\n      echo \"Invalid argument: $1\"\n      usage\n      exit 1\n      ;;\n  esac\n\n  shift\ndone\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. \"$scriptroot/tools.sh\"\n\nif [ -z \"$darcVersion\" ]; then\n  darcVersion=$(curl -X GET \"$versionEndpoint\" -H \"accept: text/plain\")\nfi\n\nfunction InstallDarcCli {\n  local darc_cli_package_name=\"microsoft.dotnet.darc\"\n\n  InitializeDotNetCli true\n  local dotnet_root=$_InitializeDotNetCli\n\n  if [ -z \"$toolpath\" ]; then\n    local tool_list=$($dotnet_root/dotnet tool list -g)\n    if [[ $tool_list = *$darc_cli_package_name* ]]; then\n      echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name -g)\n    fi\n  else\n    local tool_list=$($dotnet_root/dotnet tool list --tool-path \"$toolpath\")\n    if [[ $tool_list = *$darc_cli_package_name* ]]; then\n      echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name --tool-path \"$toolpath\")\n    fi\n  fi\n\n  local arcadeServicesSource=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json\"\n\n  echo \"Installing Darc CLI version $darcVersion...\"\n  echo \"You may need to restart your command shell if this is the first dotnet tool you have installed.\"\n  if [ -z \"$toolpath\" ]; then\n    echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source \"$arcadeServicesSource\" -v $verbosity -g)\n  else\n    echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source \"$arcadeServicesSource\" -v $verbosity --tool-path \"$toolpath\")\n  fi\n}\n\nInstallDarcCli\n"
  },
  {
    "path": "eng/common/dotnet-install.cmd",
    "content": "@echo off\npowershell -ExecutionPolicy ByPass -NoProfile -command \"& \"\"\"%~dp0dotnet-install.ps1\"\"\" %*\""
  },
  {
    "path": "eng/common/dotnet-install.ps1",
    "content": "[CmdletBinding(PositionalBinding=$false)]\nParam(\n  [string] $verbosity = 'minimal',\n  [string] $architecture = '',\n  [string] $version = 'Latest',\n  [string] $runtime = 'dotnet',\n  [string] $RuntimeSourceFeed = '',\n  [string] $RuntimeSourceFeedKey = ''\n)\n\n. $PSScriptRoot\\tools.ps1\n\n$dotnetRoot = Join-Path $RepoRoot '.dotnet'\n\n$installdir = $dotnetRoot\ntry {\n    if ($architecture -and $architecture.Trim() -eq 'x86') {\n        $installdir = Join-Path $installdir 'x86'\n    }\n    InstallDotNet $installdir $version $architecture $runtime $true -RuntimeSourceFeed $RuntimeSourceFeed -RuntimeSourceFeedKey $RuntimeSourceFeedKey\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_\n  ExitWithExitCode 1\n}\n\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/dotnet-install.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. \"$scriptroot/tools.sh\"\n\nversion='Latest'\narchitecture=''\nruntime='dotnet'\nruntimeSourceFeed=''\nruntimeSourceFeedKey=''\nwhile [[ $# > 0 ]]; do\n  opt=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n  case \"$opt\" in\n    -version|-v)\n      shift\n      version=\"$1\"\n      ;;\n    -architecture|-a)\n      shift\n      architecture=\"$1\"\n      ;;\n    -runtime|-r)\n      shift\n      runtime=\"$1\"\n      ;;\n    -runtimesourcefeed)\n      shift\n      runtimeSourceFeed=\"$1\"\n      ;;\n    -runtimesourcefeedkey)\n      shift\n      runtimeSourceFeedKey=\"$1\"\n      ;;\n    *)\n      Write-PipelineTelemetryError -Category 'Build' -Message \"Invalid argument: $1\"\n      exit 1\n      ;;\n  esac\n  shift\ndone\n\n# Use uname to determine what the CPU is, see https://en.wikipedia.org/wiki/Uname#Examples\ncpuname=$(uname -m)\ncase $cpuname in\n  arm64|aarch64)\n    buildarch=arm64\n    if [ \"$(getconf LONG_BIT)\" -lt 64 ]; then\n        # This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)\n        buildarch=arm\n    fi\n    ;;\n  loongarch64)\n    buildarch=loongarch64\n    ;;\n  amd64|x86_64)\n    buildarch=x64\n    ;;\n  armv*l)\n    buildarch=arm\n    ;;\n  i[3-6]86)\n    buildarch=x86\n    ;;\n  riscv64)\n    buildarch=riscv64\n    ;;\n  *)\n    echo \"Unknown CPU $cpuname detected, treating it as x64\"\n    buildarch=x64\n    ;;\nesac\n\ndotnetRoot=\"${repo_root}.dotnet\"\nif [[ $architecture != \"\" ]] && [[ $architecture != $buildarch ]]; then\n  dotnetRoot=\"$dotnetRoot/$architecture\"\nfi\n\nInstallDotNet \"$dotnetRoot\" $version \"$architecture\" $runtime true $runtimeSourceFeed $runtimeSourceFeedKey || {\n  local exit_code=$?\n  Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"dotnet-install.sh failed (exit code '$exit_code').\" >&2\n  ExitWithExitCode $exit_code\n}\n\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/dotnet.cmd",
    "content": "@echo off\n\n:: This script is used to install the .NET SDK.\n:: It will also invoke the SDK with any provided arguments.\n\npowershell -ExecutionPolicy ByPass -NoProfile -command \"& \"\"\"%~dp0dotnet.ps1\"\"\" %*\"\nexit /b %ErrorLevel%\n"
  },
  {
    "path": "eng/common/dotnet.ps1",
    "content": "# This script is used to install the .NET SDK.\n# It will also invoke the SDK with any provided arguments.\n\n. $PSScriptRoot\\tools.ps1\n$dotnetRoot = InitializeDotNetCli -install:$true\n\n# Invoke acquired SDK with args if they are provided\nif ($args.count -gt 0) {\n  $env:DOTNET_NOLOGO=1\n  & \"$dotnetRoot\\dotnet.exe\" $args\n}\n"
  },
  {
    "path": "eng/common/dotnet.sh",
    "content": "#!/usr/bin/env bash\n\n# This script is used to install the .NET SDK.\n# It will also invoke the SDK with any provided arguments.\n\nsource=\"${BASH_SOURCE[0]}\"\n# resolve $SOURCE until the file is no longer a symlink\nwhile [[ -h $source ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nsource $scriptroot/tools.sh\nInitializeDotNetCli true # install\n\n# Invoke acquired SDK with args if they are provided\nif [[ $# > 0 ]]; then\n  __dotnetDir=${_InitializeDotNetCli}\n  dotnetPath=${__dotnetDir}/dotnet\n  ${dotnetPath} \"$@\"\nfi\n"
  },
  {
    "path": "eng/common/enable-cross-org-publishing.ps1",
    "content": "param(\n  [string] $token\n)\n\n\n. $PSScriptRoot\\pipeline-logging-functions.ps1\n\n# Write-PipelineSetVariable will no-op if a variable named $ci is not defined\n# Since this script is only ever called in AzDO builds, just universally set it\n$ci = $true\n\nWrite-PipelineSetVariable -Name 'VSS_NUGET_ACCESSTOKEN' -Value $token -IsMultiJobVariable $false\nWrite-PipelineSetVariable -Name 'VSS_NUGET_URI_PREFIXES' -Value 'https://dnceng.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/dnceng/;https://devdiv.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/devdiv/' -IsMultiJobVariable $false\n"
  },
  {
    "path": "eng/common/generate-locproject.ps1",
    "content": "Param(\n    [Parameter(Mandatory=$true)][string] $SourcesDirectory,     # Directory where source files live; if using a Localize directory it should live in here\n    [string] $LanguageSet = 'VS_Main_Languages',                # Language set to be used in the LocProject.json\n    [switch] $UseCheckedInLocProjectJson,                       # When set, generates a LocProject.json and compares it to one that already exists in the repo; otherwise just generates one\n    [switch] $CreateNeutralXlfs                                 # Creates neutral xlf files. Only set to false when running locally\n)\n\n# Generates LocProject.json files for the OneLocBuild task. OneLocBuildTask is described here:\n# https://ceapex.visualstudio.com/CEINTL/_wiki/wikis/CEINTL.wiki/107/Localization-with-OneLocBuild-Task\n\nSet-StrictMode -Version 2.0\n$ErrorActionPreference = \"Stop\"\n. $PSScriptRoot\\pipeline-logging-functions.ps1\n\n$exclusionsFilePath = \"$SourcesDirectory\\eng\\Localize\\LocExclusions.json\"\n$exclusions = @{ Exclusions = @() }\nif (Test-Path -Path $exclusionsFilePath)\n{\n    $exclusions = Get-Content \"$exclusionsFilePath\" | ConvertFrom-Json\n}\n\nPush-Location \"$SourcesDirectory\" # push location for Resolve-Path -Relative to work\n\n# Template files\n$jsonFiles = @()\n$jsonTemplateFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\" | Where-Object { $_.FullName -Match \"\\.template\\.config\\\\localize\\\\.+\\.en\\.json\" } # .NET templating pattern\n$jsonTemplateFiles | ForEach-Object {\n    $null = $_.Name -Match \"(.+)\\.[\\w-]+\\.json\" # matches '[filename].[langcode].json\n\n    $destinationFile = \"$($_.Directory.FullName)\\$($Matches.1).json\"\n    $jsonFiles += Copy-Item \"$($_.FullName)\" -Destination $destinationFile -PassThru\n}\n\n$jsonWinformsTemplateFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\" | Where-Object { $_.FullName -Match \"en\\\\strings\\.json\" } # current winforms pattern\n\n$wxlFilesV3 = @()\n$wxlFilesV5 = @()\n$wxlFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\" | Where-Object { $_.FullName -Match \"\\\\.+\\.wxl\" -And -Not( $_.Directory.Name -Match \"\\d{4}\" ) } # localized files live in four digit lang ID directories; this excludes them\nif (-not $wxlFiles) {\n    $wxlEnFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\" | Where-Object { $_.FullName -Match \"\\\\1033\\\\.+\\.wxl\" } #  pick up en files (1033 = en) specifically so we can copy them to use as the neutral xlf files\n    if ($wxlEnFiles) {\n        $wxlFiles = @()\n        $wxlEnFiles | ForEach-Object {\n            $destinationFile = \"$($_.Directory.Parent.FullName)\\$($_.Name)\"\n            $content = Get-Content $_.FullName -Raw\n\n            # Split files on schema to select different parser settings in the generated project.\n            if ($content -like \"*http://wixtoolset.org/schemas/v4/wxl*\")\n            {\n                $wxlFilesV5 += Copy-Item $_.FullName -Destination $destinationFile -PassThru\n            }\n            elseif ($content -like \"*http://schemas.microsoft.com/wix/2006/localization*\")\n            {\n                $wxlFilesV3 += Copy-Item $_.FullName -Destination $destinationFile -PassThru\n            }\n        }\n    }\n}\n\n$macosHtmlEnFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\" | Where-Object { $_.FullName -Match \"en\\.lproj\\\\.+\\.html$\" } # add installer HTML files\n$macosHtmlFiles = @()\nif ($macosHtmlEnFiles) {\n    $macosHtmlEnFiles | ForEach-Object {\n        $destinationFile = \"$($_.Directory.Parent.FullName)\\$($_.Name)\"\n        $macosHtmlFiles += Copy-Item \"$($_.FullName)\" -Destination $destinationFile -PassThru\n    }\n}\n\n$xlfFiles = @()\n\n$allXlfFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\\*\\*.xlf\"\n$langXlfFiles = @()\nif ($allXlfFiles) {\n    $null = $allXlfFiles[0].FullName -Match \"\\.([\\w-]+)\\.xlf\" # matches '[langcode].xlf'\n    $firstLangCode = $Matches.1\n    $langXlfFiles = Get-ChildItem -Recurse -Path \"$SourcesDirectory\\*\\*.$firstLangCode.xlf\"\n}\n$langXlfFiles | ForEach-Object {\n    $null = $_.Name -Match \"(.+)\\.[\\w-]+\\.xlf\" # matches '[filename].[langcode].xlf\n\n    $destinationFile = \"$($_.Directory.FullName)\\$($Matches.1).xlf\"\n    $xlfFiles += Copy-Item \"$($_.FullName)\" -Destination $destinationFile -PassThru\n}\n\n$locFiles = $jsonFiles + $jsonWinformsTemplateFiles + $xlfFiles\n\n$locJson = @{\n    Projects = @(\n        @{\n            LanguageSet = $LanguageSet\n            LocItems = @(\n                $locFiles | ForEach-Object {\n                    $outputPath = \"$(($_.DirectoryName | Resolve-Path -Relative) + \"\\\")\"\n                    $continue = $true\n                    foreach ($exclusion in $exclusions.Exclusions) {\n                        if ($_.FullName.Contains($exclusion))\n                        {\n                            $continue = $false\n                        }\n                    }\n                    $sourceFile = ($_.FullName | Resolve-Path -Relative)\n                    if (!$CreateNeutralXlfs -and $_.Extension -eq '.xlf') {\n                        Remove-Item -Path $sourceFile\n                    }\n                    if ($continue)\n                    {\n                        if ($_.Directory.Name -eq 'en' -and $_.Extension -eq '.json') {\n                            return @{\n                                SourceFile = $sourceFile\n                                CopyOption = \"LangIDOnPath\"\n                                OutputPath = \"$($_.Directory.Parent.FullName | Resolve-Path -Relative)\\\"\n                            }\n                        } else {\n                            return @{\n                                SourceFile = $sourceFile\n                                CopyOption = \"LangIDOnName\"\n                                OutputPath = $outputPath\n                            }\n                        }\n                    }\n                }\n            )\n        },\n        @{\n            LanguageSet = $LanguageSet\n            CloneLanguageSet = \"WiX_CloneLanguages\"\n            LssFiles = @( \"wxl_loc.lss\" )\n            LocItems = @(\n                $wxlFilesV3 | ForEach-Object {\n                    $outputPath = \"$($_.Directory.FullName | Resolve-Path -Relative)\\\"\n                    $continue = $true\n                    foreach ($exclusion in $exclusions.Exclusions) {\n                        if ($_.FullName.Contains($exclusion)) {\n                            $continue = $false\n                        }\n                    }\n                    $sourceFile = ($_.FullName | Resolve-Path -Relative)\n                    if ($continue)\n                    {\n                        return @{\n                            SourceFile = $sourceFile\n                            CopyOption = \"LangIDOnPath\"\n                            OutputPath = $outputPath\n                        }\n                    }\n                }\n            )\n        },\n        @{\n            LanguageSet = $LanguageSet\n            CloneLanguageSet = \"WiX_CloneLanguages\"\n            LssFiles = @( \"P210WxlSchemaV4.lss\" )\n            LocItems = @(\n                $wxlFilesV5 | ForEach-Object {\n                    $outputPath = \"$($_.Directory.FullName | Resolve-Path -Relative)\\\"\n                    $continue = $true\n                    foreach ($exclusion in $exclusions.Exclusions) {\n                        if ($_.FullName.Contains($exclusion)) {\n                            $continue = $false\n                        }\n                    }\n                    $sourceFile = ($_.FullName | Resolve-Path -Relative)\n                    if ($continue)\n                    {\n                        return @{\n                            SourceFile = $sourceFile\n                            CopyOption = \"LangIDOnPath\"\n                            OutputPath = $outputPath\n                        }\n                    }\n                }\n            )\n        },\n        @{\n            LanguageSet = $LanguageSet\n            CloneLanguageSet = \"VS_macOS_CloneLanguages\"\n            LssFiles = @( \".\\eng\\common\\loc\\P22DotNetHtmlLocalization.lss\" )\n            LocItems = @(\n                $macosHtmlFiles | ForEach-Object {\n                    $outputPath = \"$($_.Directory.FullName | Resolve-Path -Relative)\\\"\n                    $continue = $true\n                    foreach ($exclusion in $exclusions.Exclusions) {\n                        if ($_.FullName.Contains($exclusion)) {\n                            $continue = $false\n                        }\n                    }\n                    $sourceFile = ($_.FullName | Resolve-Path -Relative)\n                    $lciFile = $sourceFile + \".lci\"\n                    if ($continue) {\n                        $result = @{\n                            SourceFile = $sourceFile\n                            CopyOption = \"LangIDOnPath\"\n                            OutputPath = $outputPath\n                        }\n                        if (Test-Path $lciFile -PathType Leaf) {\n                            $result[\"LciFile\"] = $lciFile\n                        }\n                        return $result\n                    }\n                }\n            )\n        }\n    )\n}\n\n$json = ConvertTo-Json $locJson -Depth 5\nWrite-Host \"LocProject.json generated:`n`n$json`n`n\"\nPop-Location\n\nif (!$UseCheckedInLocProjectJson) {\n    New-Item \"$SourcesDirectory\\eng\\Localize\\LocProject.json\" -Force # Need this to make sure the Localize directory is created\n    Set-Content \"$SourcesDirectory\\eng\\Localize\\LocProject.json\" $json\n}\nelse {\n    New-Item \"$SourcesDirectory\\eng\\Localize\\LocProject-generated.json\" -Force # Need this to make sure the Localize directory is created\n    Set-Content \"$SourcesDirectory\\eng\\Localize\\LocProject-generated.json\" $json\n\n    if ((Get-FileHash \"$SourcesDirectory\\eng\\Localize\\LocProject-generated.json\").Hash -ne (Get-FileHash \"$SourcesDirectory\\eng\\Localize\\LocProject.json\").Hash) {\n        Write-PipelineTelemetryError -Category \"OneLocBuild\" -Message \"Existing LocProject.json differs from generated LocProject.json. Download LocProject-generated.json and compare them.\"\n\n        exit 1\n    }\n    else {\n        Write-Host \"Generated LocProject.json and current LocProject.json are identical.\"\n    }\n}\n"
  },
  {
    "path": "eng/common/helixpublish.proj",
    "content": "<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->\n<Project Sdk=\"Microsoft.DotNet.Helix.Sdk\" DefaultTargets=\"Test\">\n\n  <PropertyGroup>\n    <Language>msbuild</Language>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <HelixCorrelationPayload Include=\"$(CorrelationPayloadDirectory)\">\n      <PayloadDirectory>%(Identity)</PayloadDirectory>\n    </HelixCorrelationPayload>\n  </ItemGroup>\n\n  <ItemGroup>\n    <HelixWorkItem Include=\"WorkItem\" Condition=\"'$(WorkItemDirectory)' != ''\">\n      <PayloadDirectory>$(WorkItemDirectory)</PayloadDirectory>\n      <Command>$(WorkItemCommand)</Command>\n      <Timeout Condition=\"'$(WorkItemTimeout)' != ''\">$(WorkItemTimeout)</Timeout>\n    </HelixWorkItem>\n  </ItemGroup>\n\n  <ItemGroup>\n    <XUnitProject Include=\"$(XUnitProjects.Split(';'))\">\n      <Arguments />\n    </XUnitProject>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "eng/common/init-tools-native.cmd",
    "content": "@echo off\npowershell -NoProfile -NoLogo -ExecutionPolicy ByPass -command \"& \"\"\"%~dp0init-tools-native.ps1\"\"\" %*\"\nexit /b %ErrorLevel%"
  },
  {
    "path": "eng/common/init-tools-native.ps1",
    "content": "<#\n.SYNOPSIS\nEntry point script for installing native tools\n\n.DESCRIPTION\nReads $RepoRoot\\global.json file to determine native assets to install\nand executes installers for those tools\n\n.PARAMETER BaseUri\nBase file directory or Url from which to acquire tool archives\n\n.PARAMETER InstallDirectory\nDirectory to install native toolset.  This is a command-line override for the default\nInstall directory precedence order:\n- InstallDirectory command-line override\n- NETCOREENG_INSTALL_DIRECTORY environment variable\n- (default) %USERPROFILE%/.netcoreeng/native\n\n.PARAMETER Clean\nSwitch specifying to not install anything, but cleanup native asset folders\n\n.PARAMETER Force\nClean and then install tools\n\n.PARAMETER DownloadRetries\nTotal number of retry attempts\n\n.PARAMETER RetryWaitTimeInSeconds\nWait time between retry attempts in seconds\n\n.PARAMETER GlobalJsonFile\nFile path to global.json file\n\n.PARAMETER PathPromotion\nOptional switch to enable either promote native tools specified in the global.json to the path (in Azure Pipelines)\nor break the build if a native tool is not found on the path (on a local dev machine)\n\n.NOTES\n#>\n[CmdletBinding(PositionalBinding=$false)]\nParam (\n  [string] $BaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external',\n  [string] $InstallDirectory,\n  [switch] $Clean = $False,\n  [switch] $Force = $False,\n  [int] $DownloadRetries = 5,\n  [int] $RetryWaitTimeInSeconds = 30,\n  [string] $GlobalJsonFile,\n  [switch] $PathPromotion\n)\n\nif (!$GlobalJsonFile) {\n  $GlobalJsonFile = Join-Path (Get-Item $PSScriptRoot).Parent.Parent.FullName 'global.json'\n}\n\nSet-StrictMode -version 2.0\n$ErrorActionPreference='Stop'\n\n. $PSScriptRoot\\pipeline-logging-functions.ps1\nImport-Module -Name (Join-Path $PSScriptRoot 'native\\CommonLibrary.psm1')\n\ntry {\n  # Define verbose switch if undefined\n  $Verbose = $VerbosePreference -Eq 'Continue'\n\n  $EngCommonBaseDir = Join-Path $PSScriptRoot 'native\\'\n  $NativeBaseDir = $InstallDirectory\n  if (!$NativeBaseDir) {\n    $NativeBaseDir = CommonLibrary\\Get-NativeInstallDirectory\n  }\n  $Env:CommonLibrary_NativeInstallDir = $NativeBaseDir\n  $InstallBin = Join-Path $NativeBaseDir 'bin'\n  $InstallerPath = Join-Path $EngCommonBaseDir 'install-tool.ps1'\n\n  # Process tools list\n  Write-Host \"Processing $GlobalJsonFile\"\n  If (-Not (Test-Path $GlobalJsonFile)) {\n    Write-Host \"Unable to find '$GlobalJsonFile'\"\n    exit 0\n  }\n  $NativeTools = Get-Content($GlobalJsonFile) -Raw |\n                    ConvertFrom-Json |\n                    Select-Object -Expand 'native-tools' -ErrorAction SilentlyContinue\n  if ($NativeTools) {\n    if ($PathPromotion -eq $True) {\n      $ArcadeToolsDirectory = \"$env:SYSTEMDRIVE\\arcade-tools\"\n      if (Test-Path $ArcadeToolsDirectory) { # if this directory exists, we should use native tools on machine\n        $NativeTools.PSObject.Properties | ForEach-Object {\n          $ToolName = $_.Name\n          $ToolVersion = $_.Value\n          $InstalledTools = @{}\n\n          if ((Get-Command \"$ToolName\" -ErrorAction SilentlyContinue) -eq $null) {\n            if ($ToolVersion -eq \"latest\") {\n              $ToolVersion = \"\"\n            }\n            $ToolDirectories = (Get-ChildItem -Path \"$ArcadeToolsDirectory\" -Filter \"$ToolName-$ToolVersion*\" | Sort-Object -Descending)\n            if ($ToolDirectories -eq $null) {\n              Write-Error \"Unable to find directory for $ToolName $ToolVersion; please make sure the tool is installed on this image.\"\n              exit 1\n            }\n            $ToolDirectory = $ToolDirectories[0]\n            $BinPathFile = \"$($ToolDirectory.FullName)\\binpath.txt\"\n            if (-not (Test-Path -Path \"$BinPathFile\")) {\n              Write-Error \"Unable to find binpath.txt in '$($ToolDirectory.FullName)' ($ToolName $ToolVersion); artifact is either installed incorrectly or is not a bootstrappable tool.\"\n              exit 1\n            }\n            $BinPath = Get-Content \"$BinPathFile\"\n            $ToolPath = Convert-Path -Path $BinPath\n            Write-Host \"Adding $ToolName to the path ($ToolPath)...\"\n            Write-Host \"##vso[task.prependpath]$ToolPath\"\n            $env:PATH = \"$ToolPath;$env:PATH\"\n            $InstalledTools += @{ $ToolName = $ToolDirectory.FullName }\n          }\n        }\n        return $InstalledTools\n      } else {\n        $NativeTools.PSObject.Properties | ForEach-Object {\n          $ToolName = $_.Name\n          $ToolVersion = $_.Value\n\n          if ((Get-Command \"$ToolName\" -ErrorAction SilentlyContinue) -eq $null) {\n            Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message \"$ToolName not found on path. Please install $ToolName $ToolVersion before proceeding.\"\n            Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message \"If this is running on a build machine, the arcade-tools directory was not found, which means there's an error with the image.\"\n          }\n        }\n        exit 0\n      }\n    } else {\n      $NativeTools.PSObject.Properties | ForEach-Object {\n        $ToolName = $_.Name\n        $ToolVersion = $_.Value\n        $LocalInstallerArguments =  @{ ToolName = \"$ToolName\" }\n        $LocalInstallerArguments += @{ InstallPath = \"$InstallBin\" }\n        $LocalInstallerArguments += @{ BaseUri = \"$BaseUri\" }\n        $LocalInstallerArguments += @{ CommonLibraryDirectory = \"$EngCommonBaseDir\" }\n        $LocalInstallerArguments += @{ Version = \"$ToolVersion\" }\n  \n        if ($Verbose) {\n          $LocalInstallerArguments += @{ Verbose = $True }\n        }\n        if (Get-Variable 'Force' -ErrorAction 'SilentlyContinue') {\n          if($Force) {\n            $LocalInstallerArguments += @{ Force = $True }\n          }\n        }\n        if ($Clean) {\n          $LocalInstallerArguments += @{ Clean = $True }\n        }\n  \n        Write-Verbose \"Installing $ToolName version $ToolVersion\"\n        Write-Verbose \"Executing '$InstallerPath $($LocalInstallerArguments.Keys.ForEach({\"-$_ '$($LocalInstallerArguments.$_)'\"}) -join ' ')'\"\n        & $InstallerPath @LocalInstallerArguments\n        if ($LASTEXITCODE -Ne \"0\") {\n          $errMsg = \"$ToolName installation failed\"\n          if ((Get-Variable 'DoNotAbortNativeToolsInstallationOnFailure' -ErrorAction 'SilentlyContinue') -and $DoNotAbortNativeToolsInstallationOnFailure) {\n              $showNativeToolsWarning = $true\n              if ((Get-Variable 'DoNotDisplayNativeToolsInstallationWarnings' -ErrorAction 'SilentlyContinue') -and $DoNotDisplayNativeToolsInstallationWarnings) {\n                  $showNativeToolsWarning = $false\n              }\n              if ($showNativeToolsWarning) {\n                  Write-Warning $errMsg\n              }\n              $toolInstallationFailure = $true\n          } else {\n              # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482\n              Write-Host $errMsg\n              exit 1\n          }\n        }\n      }\n  \n      if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {\n          # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482\n          Write-Host 'Native tools bootstrap failed'\n          exit 1\n      }\n    }\n  }\n  else {\n    Write-Host 'No native tools defined in global.json'\n    exit 0\n  }\n\n  if ($Clean) {\n    exit 0\n  }\n  if (Test-Path $InstallBin) {\n    Write-Host 'Native tools are available from ' (Convert-Path -Path $InstallBin)\n    Write-Host \"##vso[task.prependpath]$(Convert-Path -Path $InstallBin)\"\n    return $InstallBin\n  }\n  elseif (-not ($PathPromotion)) {\n    Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools install directory does not exist, installation failed'\n    exit 1\n  }\n  exit 0\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/init-tools-native.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nbase_uri='https://netcorenativeassets.blob.core.windows.net/resource-packages/external'\ninstall_directory=''\nclean=false\nforce=false\ndownload_retries=5\nretry_wait_time_seconds=30\nglobal_json_file=\"$(dirname \"$(dirname \"${scriptroot}\")\")/global.json\"\ndeclare -a native_assets\n\n. $scriptroot/pipeline-logging-functions.sh\n. $scriptroot/native/common-library.sh\n\nwhile (($# > 0)); do\n  lowerI=\"$(echo $1 | tr \"[:upper:]\" \"[:lower:]\")\"\n  case $lowerI in\n    --baseuri)\n      base_uri=$2\n      shift 2\n      ;;\n    --installdirectory)\n      install_directory=$2\n      shift 2\n      ;;\n    --clean)\n      clean=true\n      shift 1\n      ;;\n    --force)\n      force=true\n      shift 1\n      ;;\n    --donotabortonfailure)\n      donotabortonfailure=true\n      shift 1\n      ;;\n    --donotdisplaywarnings)\n      donotdisplaywarnings=true\n      shift 1\n      ;;\n    --downloadretries)\n      download_retries=$2\n      shift 2\n      ;;\n    --retrywaittimeseconds)\n      retry_wait_time_seconds=$2\n      shift 2\n      ;;\n    --help)\n      echo \"Common settings:\"\n      echo \"  --installdirectory                  Directory to install native toolset.\"\n      echo \"                                      This is a command-line override for the default\"\n      echo \"                                      Install directory precedence order:\"\n      echo \"                                          - InstallDirectory command-line override\"\n      echo \"                                          - NETCOREENG_INSTALL_DIRECTORY environment variable\"\n      echo \"                                          - (default) %USERPROFILE%/.netcoreeng/native\"\n      echo \"\"\n      echo \"  --clean                             Switch specifying not to install anything, but cleanup native asset folders\"\n      echo \"  --donotabortonfailure               Switch specifiying whether to abort native tools installation on failure\"\n      echo \"  --donotdisplaywarnings              Switch specifiying whether to display warnings during native tools installation on failure\"\n      echo \"  --force                             Clean and then install tools\"\n      echo \"  --help                              Print help and exit\"\n      echo \"\"\n      echo \"Advanced settings:\"\n      echo \"  --baseuri <value>                   Base URI for where to download native tools from\"\n      echo \"  --downloadretries <value>           Number of times a download should be attempted\"\n      echo \"  --retrywaittimeseconds <value>      Wait time between download attempts\"\n      echo \"\"\n      exit 0\n      ;;\n  esac\ndone\n\nfunction ReadGlobalJsonNativeTools {\n  # happy path: we have a proper JSON parsing tool `jq(1)` in PATH!\n  if command -v jq &> /dev/null; then\n\n    # jq: read each key/value pair under \"native-tools\" entry and emit:\n    #   KEY=\"<entry-key>\" VALUE=\"<entry-value>\"\n    # followed by a null byte.\n    #\n    # bash: read line with null byte delimeter and push to array (for later `eval`uation).\n\n    while IFS= read -rd '' line; do\n      native_assets+=(\"$line\")\n    done < <(jq -r '. |\n        select(has(\"native-tools\")) |\n        .\"native-tools\" |\n        keys[] as $k |\n        @sh \"KEY=\\($k) VALUE=\\(.[$k])\\u0000\"' \"$global_json_file\")\n\n    return\n  fi\n\n  # Warning: falling back to manually parsing JSON, which is not recommended.\n\n  # Following routine matches the output and escaping logic of jq(1)'s @sh formatter used above.\n  # It has been tested with several weird strings with escaped characters in entries (key and value)\n  # and results were compared with the output of jq(1) in binary representation using xxd(1);\n  # just before the assignment to 'native_assets' array (above and below).\n\n  # try to capture the section under \"native-tools\".\n  if [[ ! \"$(cat \"$global_json_file\")\" =~ \\\"native-tools\\\"[[:space:]\\:\\{]*([^\\}]+) ]]; then\n    return\n  fi\n\n  section=\"${BASH_REMATCH[1]}\"\n\n  parseStarted=0\n  possibleEnd=0\n  escaping=0\n  escaped=0\n  isKey=1\n\n  for (( i=0; i<${#section}; i++ )); do\n    char=\"${section:$i:1}\"\n    if ! ((parseStarted)) && [[ \"$char\" =~ [[:space:],:] ]]; then continue; fi\n\n    if ! ((escaping)) && [[ \"$char\" == \"\\\\\" ]]; then\n      escaping=1\n    elif ((escaping)) && ! ((escaped)); then\n      escaped=1\n    fi\n\n    if ! ((parseStarted)) && [[ \"$char\" == \"\\\"\" ]]; then\n      parseStarted=1\n      possibleEnd=0\n    elif [[ \"$char\" == \"'\" ]]; then\n      token=\"$token'\\\\\\''\"\n      possibleEnd=0\n    elif ((escaping)) || [[ \"$char\" != \"\\\"\" ]]; then\n      token=\"$token$char\"\n      possibleEnd=1\n    fi\n\n    if ((possibleEnd)) && ! ((escaping)) && [[ \"$char\" == \"\\\"\" ]]; then\n      # Use printf to unescape token to match jq(1)'s @sh formatting rules.\n      # do not use 'token=\"$(printf \"$token\")\"' syntax, as $() eats the trailing linefeed.\n      printf -v token \"'$token'\"\n\n      if ((isKey)); then\n        KEY=\"$token\"\n        isKey=0\n      else\n        line=\"KEY=$KEY VALUE=$token\"\n        native_assets+=(\"$line\")\n        isKey=1\n      fi\n\n      # reset for next token\n      parseStarted=0\n      token=\n    elif ((escaping)) && ((escaped)); then\n      escaping=0\n      escaped=0\n    fi\n  done\n}\n\nnative_base_dir=$install_directory\nif [[ -z $install_directory ]]; then\n  native_base_dir=$(GetNativeInstallDirectory)\nfi\n\ninstall_bin=\"${native_base_dir}/bin\"\ninstalled_any=false\n\nReadGlobalJsonNativeTools\n\nif [[ ${#native_assets[@]} -eq 0 ]]; then\n  echo \"No native tools defined in global.json\"\n  exit 0;\nelse\n  native_installer_dir=\"$scriptroot/native\"\n  for index in \"${!native_assets[@]}\"; do\n    eval \"${native_assets[\"$index\"]}\"\n\n    installer_path=\"$native_installer_dir/install-$KEY.sh\"\n    installer_command=\"$installer_path\"\n    installer_command+=\" --baseuri $base_uri\"\n    installer_command+=\" --installpath $install_bin\"\n    installer_command+=\" --version $VALUE\"\n    echo $installer_command\n\n    if [[ $force = true ]]; then\n      installer_command+=\" --force\"\n    fi\n\n    if [[ $clean = true ]]; then\n      installer_command+=\" --clean\"\n    fi\n\n    if [[ -a $installer_path ]]; then\n      $installer_command\n      if [[ $? != 0 ]]; then\n        if [[ $donotabortonfailure = true ]]; then\n          if [[ $donotdisplaywarnings != true ]]; then\n            Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Execution Failed\"\n          fi\n        else\n          Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Execution Failed\"\n          exit 1\n        fi\n      else\n        $installed_any = true\n      fi\n    else\n      if [[ $donotabortonfailure == true ]]; then\n        if [[ $donotdisplaywarnings != true ]]; then\n          Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Execution Failed: no install script\"\n        fi\n      else\n        Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Execution Failed: no install script\"\n        exit 1\n      fi\n    fi\n  done\nfi\n\nif [[ $clean = true ]]; then\n  exit 0\nfi\n\nif [[ -d $install_bin ]]; then\n  echo \"Native tools are available from $install_bin\"\n  echo \"##vso[task.prependpath]$install_bin\"\nelse\n  if [[ $installed_any = true ]]; then\n    Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Native tools install directory does not exist, installation failed\"\n    exit 1\n  fi\nfi\n\nexit 0\n"
  },
  {
    "path": "eng/common/internal/Directory.Build.props",
    "content": "<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->\n<Project>\n\n  <PropertyGroup>\n    <ImportDirectoryBuildTargets>false</ImportDirectoryBuildTargets>\n    <ImportDirectoryPackagesProps>false</ImportDirectoryPackagesProps>\n  </PropertyGroup>\n\n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.DotNet.Arcade.Sdk\" />\n\n</Project>\n"
  },
  {
    "path": "eng/common/internal/NuGet.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <add key=\"dotnet-core-internal-tooling\" value=\"https://pkgs.dev.azure.com/devdiv/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json\" />\n  </packageSources>\n  <packageSourceMapping>\n    <clear />\n  </packageSourceMapping>\n</configuration>\n"
  },
  {
    "path": "eng/common/internal/Tools.csproj",
    "content": "<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->\n<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n    <AutomaticallyUseReferenceAssemblyPackages>false</AutomaticallyUseReferenceAssemblyPackages>\n    <BuildWithNetFrameworkHostedCompiler>false</BuildWithNetFrameworkHostedCompiler>\n  </PropertyGroup>\n  <ItemGroup>\n    <!-- Clear references, the SDK may add some depending on UsuingToolXxx settings, but we only want to restore the following -->\n    <PackageReference Remove=\"@(PackageReference)\"/>\n    <PackageReference Include=\"Microsoft.ManifestTool.CrossPlatform\" Version=\"$(MicrosoftManifestToolCrossPlatformVersion)\" />\n    <PackageReference Include=\"Microsoft.VisualStudioEng.MicroBuild.Core\" Version=\"$(MicrosoftVisualStudioEngMicroBuildCoreVersion)\" />\n    <PackageReference Include=\"Microsoft.VisualStudioEng.MicroBuild.Plugins.SwixBuild\" Version=\"$(MicrosoftVisualStudioEngMicroBuildPluginsSwixBuildVersion)\" />\n    <PackageReference Include=\"Microsoft.DotNet.IBCMerge\" Version=\"$(MicrosoftDotNetIBCMergeVersion)\" Condition=\"'$(UsingToolIbcOptimization)' == 'true'\" />\n    <PackageReference Include=\"Drop.App\" Version=\"$(DropAppVersion)\" ExcludeAssets=\"all\" Condition=\"'$(UsingToolVisualStudioIbcTraining)' == 'true'\"/>\n  </ItemGroup>\n\n  <!-- Repository extensibility point -->\n  <Import Project=\"$(RepositoryEngineeringDir)InternalTools.props\" Condition=\"Exists('$(RepositoryEngineeringDir)InternalTools.props')\" />\n\n</Project>\n"
  },
  {
    "path": "eng/common/internal-feed-operations.ps1",
    "content": "param(\n  [Parameter(Mandatory=$true)][string] $Operation,\n  [string] $AuthToken,\n  [string] $CommitSha,\n  [string] $RepoName,\n  [switch] $IsFeedPrivate\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n. $PSScriptRoot\\tools.ps1\n\n# Sets VSS_NUGET_EXTERNAL_FEED_ENDPOINTS based on the \"darc-int-*\" feeds defined in NuGet.config. This is needed\n# in build agents by CredProvider to authenticate the restore requests to internal feeds as specified in\n# https://github.com/microsoft/artifacts-credprovider/blob/0f53327cd12fd893d8627d7b08a2171bf5852a41/README.md#environment-variables. This should ONLY be called from identified\n# internal builds\nfunction SetupCredProvider {\n  param(\n    [string] $AuthToken\n  )    \n\n  # Install the Cred Provider NuGet plugin\n  Write-Host 'Setting up Cred Provider NuGet plugin in the agent...'\n  Write-Host \"Getting 'installcredprovider.ps1' from 'https://github.com/microsoft/artifacts-credprovider'...\"\n\n  $url = 'https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1'\n  \n  Write-Host \"Writing the contents of 'installcredprovider.ps1' locally...\"\n  Invoke-WebRequest $url -UseBasicParsing -OutFile installcredprovider.ps1\n  \n  Write-Host 'Installing plugin...'\n  .\\installcredprovider.ps1 -Force\n  \n  Write-Host \"Deleting local copy of 'installcredprovider.ps1'...\"\n  Remove-Item .\\installcredprovider.ps1\n\n  if (-Not(\"$env:USERPROFILE\\.nuget\\plugins\\netcore\")) {\n    Write-PipelineTelemetryError -Category 'Arcade' -Message 'CredProvider plugin was not installed correctly!'\n    ExitWithExitCode 1  \n  } \n  else {\n    Write-Host 'CredProvider plugin was installed correctly!'\n  }\n\n  # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable \n  # feeds successfully\n\n  $nugetConfigPath = Join-Path $RepoRoot \"NuGet.config\"\n\n  if (-Not (Test-Path -Path $nugetConfigPath)) {\n    Write-PipelineTelemetryError -Category 'Build' -Message 'NuGet.config file not found in repo root!'\n    ExitWithExitCode 1\n  }\n  \n  $endpoints = New-Object System.Collections.ArrayList\n  $nugetConfigPackageSources = Select-Xml -Path $nugetConfigPath -XPath \"//packageSources/add[contains(@key, 'darc-int-')]/@value\" | foreach{$_.Node.Value}\n  \n  if (($nugetConfigPackageSources | Measure-Object).Count -gt 0 ) {\n    foreach ($stableRestoreResource in $nugetConfigPackageSources) {\n      $trimmedResource = ([string]$stableRestoreResource).Trim()\n      [void]$endpoints.Add(@{endpoint=\"$trimmedResource\"; password=\"$AuthToken\"}) \n    }\n  }\n\n  if (($endpoints | Measure-Object).Count -gt 0) {\n      $endpointCredentials = @{endpointCredentials=$endpoints} | ConvertTo-Json -Compress\n\n     # Create the environment variables the AzDo way\n      Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $endpointCredentials -Properties @{\n        'variable' = 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'\n        'issecret' = 'false'\n      } \n\n      # We don't want sessions cached since we will be updating the endpoints quite frequently\n      Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data 'False' -Properties @{\n        'variable' = 'NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED'\n        'issecret' = 'false'\n      } \n  }\n  else\n  {\n    Write-Host 'No internal endpoints found in NuGet.config'\n  }\n}\n\n#Workaround for https://github.com/microsoft/msbuild/issues/4430\nfunction InstallDotNetSdkAndRestoreArcade {\n  $dotnetTempDir = Join-Path $RepoRoot \"dotnet\"\n  $dotnetSdkVersion=\"2.1.507\" # After experimentation we know this version works when restoring the SDK (compared to 3.0.*)\n  $dotnet = \"$dotnetTempDir\\dotnet.exe\"\n  $restoreProjPath = \"$PSScriptRoot\\restore.proj\"\n  \n  Write-Host \"Installing dotnet SDK version $dotnetSdkVersion to restore Arcade SDK...\"\n  InstallDotNetSdk \"$dotnetTempDir\" \"$dotnetSdkVersion\"\n  \n  '<Project Sdk=\"Microsoft.DotNet.Arcade.Sdk\"/>' | Out-File \"$restoreProjPath\"\n\n  & $dotnet restore $restoreProjPath\n\n  Write-Host 'Arcade SDK restored!'\n\n  if (Test-Path -Path $restoreProjPath) {\n    Remove-Item $restoreProjPath\n  }\n\n  if (Test-Path -Path $dotnetTempDir) {\n    Remove-Item $dotnetTempDir -Recurse\n  }\n}\n\ntry {\n  Push-Location $PSScriptRoot\n\n  if ($Operation -like 'setup') {\n    SetupCredProvider $AuthToken\n  } \n  elseif ($Operation -like 'install-restore') {\n    InstallDotNetSdkAndRestoreArcade\n  }\n  else {\n    Write-PipelineTelemetryError -Category 'Arcade' -Message \"Unknown operation '$Operation'!\"\n    ExitWithExitCode 1  \n  }\n} \ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'Arcade' -Message $_\n  ExitWithExitCode 1\n} \nfinally {\n  Pop-Location\n}\n"
  },
  {
    "path": "eng/common/internal-feed-operations.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\n# Sets VSS_NUGET_EXTERNAL_FEED_ENDPOINTS based on the \"darc-int-*\" feeds defined in NuGet.config. This is needed\n# in build agents by CredProvider to authenticate the restore requests to internal feeds as specified in\n# https://github.com/microsoft/artifacts-credprovider/blob/0f53327cd12fd893d8627d7b08a2171bf5852a41/README.md#environment-variables. \n# This should ONLY be called from identified internal builds\nfunction SetupCredProvider {\n  local authToken=$1\n  \n  # Install the Cred Provider NuGet plugin\n  echo \"Setting up Cred Provider NuGet plugin in the agent...\"...\n  echo \"Getting 'installcredprovider.ps1' from 'https://github.com/microsoft/artifacts-credprovider'...\"\n\n  local url=\"https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh\"  \n  \n  echo \"Writing the contents of 'installcredprovider.ps1' locally...\"\n  local installcredproviderPath=\"installcredprovider.sh\"\n  if command -v curl > /dev/null; then\n    curl $url > \"$installcredproviderPath\"\n  else   \n    wget -q -O \"$installcredproviderPath\" \"$url\"\n  fi\n  \n  echo \"Installing plugin...\"\n  . \"$installcredproviderPath\"\n  \n  echo \"Deleting local copy of 'installcredprovider.sh'...\"\n  rm installcredprovider.sh\n\n  if [ ! -d \"$HOME/.nuget/plugins\" ]; then\n    Write-PipelineTelemetryError -category 'Build' 'CredProvider plugin was not installed correctly!'\n    ExitWithExitCode 1  \n  else \n    echo \"CredProvider plugin was installed correctly!\"\n  fi\n\n  # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable \n  # feeds successfully\n\n  local nugetConfigPath=\"{$repo_root}NuGet.config\"\n\n  if [ ! \"$nugetConfigPath\" ]; then\n    Write-PipelineTelemetryError -category 'Build' \"NuGet.config file not found in repo's root!\"\n    ExitWithExitCode 1  \n  fi\n  \n  local endpoints='['\n  local nugetConfigPackageValues=`cat \"$nugetConfigPath\" | grep \"key=\\\"darc-int-\"`\n  local pattern=\"value=\\\"(.*)\\\"\"\n\n  for value in $nugetConfigPackageValues \n  do\n    if [[ $value =~ $pattern ]]; then\n      local endpoint=\"${BASH_REMATCH[1]}\"  \n      endpoints+=\"{\\\"endpoint\\\": \\\"$endpoint\\\", \\\"password\\\": \\\"$authToken\\\"},\"\n    fi\n  done\n  \n  endpoints=${endpoints%?}\n  endpoints+=']'\n\n  if [ ${#endpoints} -gt 2 ]; then \n      local endpointCredentials=\"{\\\"endpointCredentials\\\": \"$endpoints\"}\"\n\n      echo \"##vso[task.setvariable variable=VSS_NUGET_EXTERNAL_FEED_ENDPOINTS]$endpointCredentials\"\n      echo \"##vso[task.setvariable variable=NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED]False\"\n  else\n    echo \"No internal endpoints found in NuGet.config\"\n  fi\n} \n\n# Workaround for https://github.com/microsoft/msbuild/issues/4430\nfunction InstallDotNetSdkAndRestoreArcade {\n  local dotnetTempDir=\"$repo_root/dotnet\"\n  local dotnetSdkVersion=\"2.1.507\" # After experimentation we know this version works when restoring the SDK (compared to 3.0.*)\n  local restoreProjPath=\"$repo_root/eng/common/restore.proj\"\n  \n  echo \"Installing dotnet SDK version $dotnetSdkVersion to restore Arcade SDK...\"\n  echo \"<Project Sdk=\\\"Microsoft.DotNet.Arcade.Sdk\\\"/>\" > \"$restoreProjPath\"\n  \n  InstallDotNetSdk \"$dotnetTempDir\" \"$dotnetSdkVersion\"\n\n  local res=`$dotnetTempDir/dotnet restore $restoreProjPath`\n  echo \"Arcade SDK restored!\"\n\n  # Cleanup\n  if [ \"$restoreProjPath\" ]; then\n    rm \"$restoreProjPath\"\n  fi\n\n  if [ \"$dotnetTempDir\" ]; then\n    rm -r $dotnetTempDir\n  fi\n}\n\nsource=\"${BASH_SOURCE[0]}\"\noperation=''\nauthToken=''\nrepoName=''\n\nwhile [[ $# > 0 ]]; do\n  opt=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n  case \"$opt\" in\n    --operation)\n      operation=$2\n      shift\n      ;;\n    --authtoken)\n      authToken=$2\n      shift\n      ;;\n    *)\n      echo \"Invalid argument: $1\"\n      usage\n      exit 1\n      ;;\n  esac\n\n  shift\ndone\n\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. \"$scriptroot/tools.sh\"\n\nif [ \"$operation\" = \"setup\" ]; then\n  SetupCredProvider $authToken\nelif [ \"$operation\" = \"install-restore\" ]; then\n  InstallDotNetSdkAndRestoreArcade\nelse\n  echo \"Unknown operation '$operation'!\"\nfi\n"
  },
  {
    "path": "eng/common/loc/P22DotNetHtmlLocalization.lss",
    "content": "<?xml version=\"1.0\"?>\n<LS_SETTINGS_FILE>\n  <LS_SETTINGS_DESCRIPTION>\n    <![CDATA[]]>\n  </LS_SETTINGS_DESCRIPTION>\n  <optionSet id=\"LSOptions\">\n    <optionSet id=\"Defaults\" displayName=\"Options Defaults\">\n      <optionSet id=\"Espresso\" displayName=\"Espresso\"/>\n      <optionSet id=\"Parsers\" displayName=\"Parsers\"/>\n    </optionSet>\n    <optionSet id=\"User\" displayName=\"User Overrides\">\n      <optionSet id=\"Espresso\" displayName=\"Espresso\"/>\n      <optionSet id=\"Parsers\" displayName=\"Parsers\"/>\n    </optionSet>\n    <optionSet id=\"Project\" displayName=\"Project Overrides\">\n      <optionSet id=\"Espresso\" displayName=\"Espresso\"/>\n      <optionSet id=\"Parsers\" displayName=\"Parsers\">\n        <optionSet id=\"Parser 22\" displayName=\"POMHTML Parser options\" helpText=\"POMHTML Parser options for Localization Studio.\">\n          <option id=\"SetCharsetInfo\" displayName=\"Set or add Charset information when Generating\" helpText=\"Add Charset information to the Generated file. This is in the format &lt;META HTTP-EQUIV=&quot;Content-Type&quot; CONTENT=&quot;text/html; charset=windows-1252&quot;&gt;. This is based on the Project Target Langauge. If the dir attribute value in the HTML tag i.e. &lt;HTML dir=&quot;ltr&quot;&gt; is not localizable or is missing, its value will be set automatically on Generate if the reading order of the target language is different from the source language.\">\n            <boolean defaultValue=\"1\" currentValue=\"0\"/>\n          </option>\n          <option id=\"IncTermNoResId\" displayName=\"Include Terms which have no Resource Identifier\" helpText=\"Include Terms which have no Resource Identifier. Terms without Resource Identifiers cannot be Updated or Uploaded if they change.\">\n            <boolean defaultValue=\"0\" currentValue=\"1\"/>\n          </option>\n        </optionSet>\n      </optionSet>\n    </optionSet>\n  </optionSet>\n</LS_SETTINGS_FILE>"
  },
  {
    "path": "eng/common/msbuild.ps1",
    "content": "[CmdletBinding(PositionalBinding=$false)]\nParam(\n  [string] $verbosity = 'minimal',\n  [bool] $warnAsError = $true,\n  [bool] $nodeReuse = $true,\n  [switch] $ci,\n  [switch] $prepareMachine,\n  [switch] $excludePrereleaseVS,\n  [string] $msbuildEngine = $null,\n  [Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs\n)\n\n. $PSScriptRoot\\tools.ps1\n\ntry {\n  if ($ci) {\n    $nodeReuse = $false\n  }\n\n  MSBuild @extraArgs\n} \ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'Build' -Message $_\n  ExitWithExitCode 1\n}\n\nExitWithExitCode 0"
  },
  {
    "path": "eng/common/msbuild.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nverbosity='minimal'\nwarn_as_error=true\nnode_reuse=true\nprepare_machine=false\nextra_args=''\n\nwhile (($# > 0)); do\n  lowerI=\"$(echo $1 | tr \"[:upper:]\" \"[:lower:]\")\"\n  case $lowerI in\n    --verbosity)\n      verbosity=$2\n      shift 2\n      ;;\n    --warnaserror)\n      warn_as_error=$2\n      shift 2\n      ;;\n    --nodereuse)\n      node_reuse=$2\n      shift 2\n      ;;\n    --ci)\n      ci=true\n      shift 1\n      ;;\n    --preparemachine)\n      prepare_machine=true\n      shift 1\n      ;;\n      *)\n      extra_args=\"$extra_args $1\"\n      shift 1\n      ;;\n  esac\ndone\n\n. \"$scriptroot/tools.sh\"\n\nif [[ \"$ci\" == true ]]; then\n  node_reuse=false\nfi\n\nMSBuild $extra_args\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/native/CommonLibrary.psm1",
    "content": "<#\n.SYNOPSIS\nHelper module to install an archive to a directory\n\n.DESCRIPTION\nHelper module to download and extract an archive to a specified directory\n\n.PARAMETER Uri\nUri of artifact to download\n\n.PARAMETER InstallDirectory\nDirectory to extract artifact contents to\n\n.PARAMETER Force\nForce download / extraction if file or contents already exist. Default = False\n\n.PARAMETER DownloadRetries\nTotal number of retry attempts. Default = 5\n\n.PARAMETER RetryWaitTimeInSeconds\nWait time between retry attempts in seconds. Default = 30\n\n.NOTES\nReturns False if download or extraction fail, True otherwise\n#>\nfunction DownloadAndExtract {\n  [CmdletBinding(PositionalBinding=$false)]\n  Param (\n    [Parameter(Mandatory=$True)]\n    [string] $Uri,\n    [Parameter(Mandatory=$True)]\n    [string] $InstallDirectory,\n    [switch] $Force = $False,\n    [int] $DownloadRetries = 5,\n    [int] $RetryWaitTimeInSeconds = 30\n  )\n  # Define verbose switch if undefined\n  $Verbose = $VerbosePreference -Eq \"Continue\"\n\n  $TempToolPath = CommonLibrary\\Get-TempPathFilename -Path $Uri\n\n  # Download native tool\n  $DownloadStatus = CommonLibrary\\Get-File -Uri $Uri `\n                                           -Path $TempToolPath `\n                                           -DownloadRetries $DownloadRetries `\n                                           -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `\n                                           -Force:$Force `\n                                           -Verbose:$Verbose\n\n  if ($DownloadStatus -Eq $False) {\n    Write-Error \"Download failed from $Uri\"\n    return $False\n  }\n\n  # Extract native tool\n  $UnzipStatus = CommonLibrary\\Expand-Zip -ZipPath $TempToolPath `\n                                          -OutputDirectory $InstallDirectory `\n                                          -Force:$Force `\n                                          -Verbose:$Verbose\n\n  if ($UnzipStatus -Eq $False) {\n    # Retry Download one more time with Force=true\n    $DownloadRetryStatus = CommonLibrary\\Get-File -Uri $Uri `\n                                             -Path $TempToolPath `\n                                             -DownloadRetries 1 `\n                                             -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `\n                                             -Force:$True `\n                                             -Verbose:$Verbose\n\n    if ($DownloadRetryStatus -Eq $False) {\n      Write-Error \"Last attempt of download failed as well\"\n      return $False\n    }\n\n    # Retry unzip again one more time with Force=true\n    $UnzipRetryStatus = CommonLibrary\\Expand-Zip -ZipPath $TempToolPath `\n                                            -OutputDirectory $InstallDirectory `\n                                            -Force:$True `\n                                            -Verbose:$Verbose\n    if ($UnzipRetryStatus -Eq $False)\n    {\n      Write-Error \"Last attempt of unzip failed as well\"\n      # Clean up partial zips and extracts\n      if (Test-Path $TempToolPath) {\n        Remove-Item $TempToolPath -Force\n      }\n      if (Test-Path $InstallDirectory) {\n        Remove-Item $InstallDirectory -Force -Recurse\n      }\n      return $False\n    }\n  }\n\n  return $True\n}\n\n<#\n.SYNOPSIS\nDownload a file, retry on failure\n\n.DESCRIPTION\nDownload specified file and retry if attempt fails\n\n.PARAMETER Uri\nUri of file to download. If Uri is a local path, the file will be copied instead of downloaded\n\n.PARAMETER Path\nPath to download or copy uri file to\n\n.PARAMETER Force\nOverwrite existing file if present. Default = False\n\n.PARAMETER DownloadRetries\nTotal number of retry attempts. Default = 5\n\n.PARAMETER RetryWaitTimeInSeconds\nWait time between retry attempts in seconds Default = 30\n\n#>\nfunction Get-File {\n  [CmdletBinding(PositionalBinding=$false)]\n  Param (\n    [Parameter(Mandatory=$True)]\n    [string] $Uri,\n    [Parameter(Mandatory=$True)]\n    [string] $Path,\n    [int] $DownloadRetries = 5,\n    [int] $RetryWaitTimeInSeconds = 30,\n    [switch] $Force = $False\n  )\n  $Attempt = 0\n\n  if ($Force) {\n    if (Test-Path $Path) {\n      Remove-Item $Path -Force\n    }\n  }\n  if (Test-Path $Path) {\n    Write-Host \"File '$Path' already exists, skipping download\"\n    return $True\n  }\n\n  $DownloadDirectory = Split-Path -ErrorAction Ignore -Path \"$Path\" -Parent\n  if (-Not (Test-Path $DownloadDirectory)) {\n    New-Item -path $DownloadDirectory -force -itemType \"Directory\" | Out-Null\n  }\n\n  $TempPath = \"$Path.tmp\"\n  if (Test-Path -IsValid -Path $Uri) {\n    Write-Verbose \"'$Uri' is a file path, copying temporarily to '$TempPath'\"\n    Copy-Item -Path $Uri -Destination $TempPath\n    Write-Verbose \"Moving temporary file to '$Path'\"\n    Move-Item -Path $TempPath -Destination $Path\n    return $?\n  }\n  else {\n    Write-Verbose \"Downloading $Uri\"\n    # Don't display the console progress UI - it's a huge perf hit\n    $ProgressPreference = 'SilentlyContinue'   \n    while($Attempt -Lt $DownloadRetries)\n    {\n      try {\n        Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $TempPath\n        Write-Verbose \"Downloaded to temporary location '$TempPath'\"\n        Move-Item -Path $TempPath -Destination $Path\n        Write-Verbose \"Moved temporary file to '$Path'\"\n        return $True\n      }\n      catch {\n        $Attempt++\n        if ($Attempt -Lt $DownloadRetries) {\n          $AttemptsLeft = $DownloadRetries - $Attempt\n          Write-Warning \"Download failed, $AttemptsLeft attempts remaining, will retry in $RetryWaitTimeInSeconds seconds\"\n          Start-Sleep -Seconds $RetryWaitTimeInSeconds\n        }\n        else {\n          Write-Error $_\n          Write-Error $_.Exception\n        }\n      }\n    }\n  }\n\n  return $False\n}\n\n<#\n.SYNOPSIS\nGenerate a shim for a native tool\n\n.DESCRIPTION\nCreates a wrapper script (shim) that passes arguments forward to native tool assembly\n\n.PARAMETER ShimName\nThe name of the shim\n\n.PARAMETER ShimDirectory\nThe directory where shims are stored\n\n.PARAMETER ToolFilePath\nPath to file that shim forwards to\n\n.PARAMETER Force\nReplace shim if already present.  Default = False\n\n.NOTES\nReturns $True if generating shim succeeds, $False otherwise\n#>\nfunction New-ScriptShim {\n  [CmdletBinding(PositionalBinding=$false)]\n  Param (\n    [Parameter(Mandatory=$True)]\n    [string] $ShimName,\n    [Parameter(Mandatory=$True)]\n    [string] $ShimDirectory,\n    [Parameter(Mandatory=$True)]\n    [string] $ToolFilePath,\n    [Parameter(Mandatory=$True)]\n    [string] $BaseUri,\n    [switch] $Force\n  )\n  try {\n    Write-Verbose \"Generating '$ShimName' shim\"\n\n    if (-Not (Test-Path $ToolFilePath)){\n      Write-Error \"Specified tool file path '$ToolFilePath' does not exist\"\n      return $False\n    }\n\n    # WinShimmer is a small .NET Framework program that creates .exe shims to bootstrapped programs\n    # Many of the checks for installed programs expect a .exe extension for Windows tools, rather\n    # than a .bat or .cmd file.\n    # Source: https://github.com/dotnet/arcade/tree/master/src/WinShimmer\n    if (-Not (Test-Path \"$ShimDirectory\\WinShimmer\\winshimmer.exe\")) {\n      $InstallStatus = DownloadAndExtract -Uri \"$BaseUri/windows/winshimmer/WinShimmer.zip\" `\n                                          -InstallDirectory $ShimDirectory\\WinShimmer `\n                                          -Force:$Force `\n                                          -DownloadRetries 2 `\n                                          -RetryWaitTimeInSeconds 5 `\n                                          -Verbose:$Verbose\n    }\n\n    if ((Test-Path (Join-Path $ShimDirectory \"$ShimName.exe\"))) {\n      Write-Host \"$ShimName.exe already exists; replacing...\"\n      Remove-Item (Join-Path $ShimDirectory \"$ShimName.exe\")\n    }\n\n    & \"$ShimDirectory\\WinShimmer\\winshimmer.exe\" $ShimName $ToolFilePath $ShimDirectory\n    return $True\n  }\n  catch {\n    Write-Host $_\n    Write-Host $_.Exception\n    return $False\n  }\n}\n\n<#\n.SYNOPSIS\nReturns the machine architecture of the host machine\n\n.NOTES\nReturns 'x64' on 64 bit machines\n Returns 'x86' on 32 bit machines\n#>\nfunction Get-MachineArchitecture {\n  $ProcessorArchitecture = $Env:PROCESSOR_ARCHITECTURE\n  $ProcessorArchitectureW6432 = $Env:PROCESSOR_ARCHITEW6432\n  if($ProcessorArchitecture -Eq \"X86\")\n  {\n    if(($ProcessorArchitectureW6432 -Eq \"\") -Or\n       ($ProcessorArchitectureW6432 -Eq \"X86\")) {\n        return \"x86\"\n    }\n    $ProcessorArchitecture = $ProcessorArchitectureW6432\n  }\n  if (($ProcessorArchitecture -Eq \"AMD64\") -Or\n      ($ProcessorArchitecture -Eq \"IA64\") -Or\n      ($ProcessorArchitecture -Eq \"ARM64\") -Or\n      ($ProcessorArchitecture -Eq \"LOONGARCH64\") -Or\n      ($ProcessorArchitecture -Eq \"RISCV64\")) {\n    return \"x64\"\n  }\n  return \"x86\"\n}\n\n<#\n.SYNOPSIS\nGet the name of a temporary folder under the native install directory\n#>\nfunction Get-TempDirectory {\n  return Join-Path (Get-NativeInstallDirectory) \"temp/\"\n}\n\nfunction Get-TempPathFilename {\n  [CmdletBinding(PositionalBinding=$false)]\n  Param (\n    [Parameter(Mandatory=$True)]\n    [string] $Path\n  )\n  $TempDir = CommonLibrary\\Get-TempDirectory\n  $TempFilename = Split-Path $Path -leaf\n  $TempPath = Join-Path $TempDir $TempFilename\n  return $TempPath\n}\n\n<#\n.SYNOPSIS\nReturns the base directory to use for native tool installation\n\n.NOTES\nReturns the value of the NETCOREENG_INSTALL_DIRECTORY if that environment variable\nis set, or otherwise returns an install directory under the %USERPROFILE%\n#>\nfunction Get-NativeInstallDirectory {\n  $InstallDir = $Env:NETCOREENG_INSTALL_DIRECTORY\n  if (!$InstallDir) {\n    $InstallDir = Join-Path $Env:USERPROFILE \".netcoreeng/native/\"\n  }\n  return $InstallDir\n}\n\n<#\n.SYNOPSIS\nUnzip an archive\n\n.DESCRIPTION\nPowershell module to unzip an archive to a specified directory\n\n.PARAMETER ZipPath (Required)\nPath to archive to unzip\n\n.PARAMETER OutputDirectory (Required)\nOutput directory for archive contents\n\n.PARAMETER Force\nOverwrite output directory contents if they already exist\n\n.NOTES\n- Returns True and does not perform an extraction if output directory already exists but Overwrite is not True.\n- Returns True if unzip operation is successful\n- Returns False if Overwrite is True and it is unable to remove contents of OutputDirectory\n- Returns False if unable to extract zip archive\n#>\nfunction Expand-Zip {\n  [CmdletBinding(PositionalBinding=$false)]\n  Param (\n    [Parameter(Mandatory=$True)]\n    [string] $ZipPath,\n    [Parameter(Mandatory=$True)]\n    [string] $OutputDirectory,\n    [switch] $Force\n  )\n\n  Write-Verbose \"Extracting '$ZipPath' to '$OutputDirectory'\"\n  try {\n    if ((Test-Path $OutputDirectory) -And (-Not $Force)) {\n      Write-Host \"Directory '$OutputDirectory' already exists, skipping extract\"\n      return $True\n    }\n    if (Test-Path $OutputDirectory) {\n      Write-Verbose \"'Force' is 'True', but '$OutputDirectory' exists, removing directory\"\n      Remove-Item $OutputDirectory -Force -Recurse\n      if ($? -Eq $False) {\n        Write-Error \"Unable to remove '$OutputDirectory'\"\n        return $False\n      }\n    }\n\n    $TempOutputDirectory = Join-Path \"$(Split-Path -Parent $OutputDirectory)\" \"$(Split-Path -Leaf $OutputDirectory).tmp\"\n    if (Test-Path $TempOutputDirectory) {\n      Remove-Item $TempOutputDirectory -Force -Recurse\n    }\n    New-Item -Path $TempOutputDirectory -Force -ItemType \"Directory\" | Out-Null\n\n    Add-Type -assembly \"system.io.compression.filesystem\"\n    [io.compression.zipfile]::ExtractToDirectory(\"$ZipPath\", \"$TempOutputDirectory\")\n    if ($? -Eq $False) {\n      Write-Error \"Unable to extract '$ZipPath'\"\n      return $False\n    }\n\n    Move-Item -Path $TempOutputDirectory -Destination $OutputDirectory\n  }\n  catch {\n    Write-Host $_\n    Write-Host $_.Exception\n\n    return $False\n  }\n  return $True\n}\n\nexport-modulemember -function DownloadAndExtract\nexport-modulemember -function Expand-Zip\nexport-modulemember -function Get-File\nexport-modulemember -function Get-MachineArchitecture\nexport-modulemember -function Get-NativeInstallDirectory\nexport-modulemember -function Get-TempDirectory\nexport-modulemember -function Get-TempPathFilename\nexport-modulemember -function New-ScriptShim\n"
  },
  {
    "path": "eng/common/native/common-library.sh",
    "content": "#!/usr/bin/env bash\n\nfunction GetNativeInstallDirectory {\n  local install_dir\n\n  if [[ -z $NETCOREENG_INSTALL_DIRECTORY ]]; then\n    install_dir=$HOME/.netcoreeng/native/\n  else\n    install_dir=$NETCOREENG_INSTALL_DIRECTORY\n  fi\n\n  echo $install_dir\n  return 0\n}\n\nfunction GetTempDirectory {\n\n  echo $(GetNativeInstallDirectory)temp/\n  return 0\n}\n\nfunction ExpandZip {\n  local zip_path=$1\n  local output_directory=$2\n  local force=${3:-false}\n\n  echo \"Extracting $zip_path to $output_directory\"\n  if [[ -d $output_directory ]] && [[ $force = false ]]; then\n    echo \"Directory '$output_directory' already exists, skipping extract\"\n    return 0\n  fi\n\n  if [[ -d $output_directory ]]; then\n    echo \"'Force flag enabled, but '$output_directory' exists. Removing directory\"\n    rm -rf $output_directory\n    if [[ $? != 0 ]]; then\n      Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Unable to remove '$output_directory'\"\n      return 1\n    fi\n  fi\n\n  echo \"Creating directory: '$output_directory'\"\n  mkdir -p $output_directory\n\n  echo \"Extracting archive\"\n  tar -xf $zip_path -C $output_directory\n  if [[ $? != 0 ]]; then\n    Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Unable to extract '$zip_path'\"\n    return 1\n  fi\n\n  return 0\n}\n\nfunction GetCurrentOS {\n  local unameOut=\"$(uname -s)\"\n  case $unameOut in\n    Linux*)     echo \"Linux\";;\n    Darwin*)    echo \"MacOS\";;\n  esac\n  return 0\n}\n\nfunction GetFile {\n  local uri=$1\n  local path=$2\n  local force=${3:-false}\n  local download_retries=${4:-5}\n  local retry_wait_time_seconds=${5:-30}\n\n  if [[ -f $path ]]; then\n    if [[ $force = false ]]; then\n      echo \"File '$path' already exists. Skipping download\"\n      return 0\n    else\n      rm -rf $path\n    fi\n  fi\n\n  if [[ -f $uri ]]; then\n    echo \"'$uri' is a file path, copying file to '$path'\"\n    cp $uri $path\n    return $?\n  fi\n\n  echo \"Downloading $uri\"\n  # Use curl if available, otherwise use wget\n  if command -v curl > /dev/null; then\n    curl \"$uri\" -sSL --retry $download_retries --retry-delay $retry_wait_time_seconds --create-dirs -o \"$path\" --fail\n  else\n    wget -q -O \"$path\" \"$uri\" --tries=\"$download_retries\"\n  fi\n\n  return $?\n}\n\nfunction GetTempPathFileName {\n  local path=$1\n\n  local temp_dir=$(GetTempDirectory)\n  local temp_file_name=$(basename $path)\n  echo $temp_dir$temp_file_name\n  return 0\n}\n\nfunction DownloadAndExtract {\n  local uri=$1\n  local installDir=$2\n  local force=${3:-false}\n  local download_retries=${4:-5}\n  local retry_wait_time_seconds=${5:-30}\n\n  local temp_tool_path=$(GetTempPathFileName $uri)\n\n  echo \"downloading to: $temp_tool_path\"\n\n  # Download file\n  GetFile \"$uri\" \"$temp_tool_path\" $force $download_retries $retry_wait_time_seconds\n  if [[ $? != 0 ]]; then\n    Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Failed to download '$uri' to '$temp_tool_path'.\"\n    return 1\n  fi\n\n  # Extract File\n  echo \"extracting from  $temp_tool_path to $installDir\"\n  ExpandZip \"$temp_tool_path\" \"$installDir\" $force $download_retries $retry_wait_time_seconds\n  if [[ $? != 0 ]]; then\n    Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Failed to extract '$temp_tool_path' to '$installDir'.\"\n    return 1\n  fi\n\n  return 0\n}\n\nfunction NewScriptShim {\n  local shimpath=$1\n  local tool_file_path=$2\n  local force=${3:-false}\n\n  echo \"Generating '$shimpath' shim\"\n  if [[ -f $shimpath ]]; then\n    if [[ $force = false ]]; then\n      echo \"File '$shimpath' already exists.\" >&2\n      return 1\n    else\n      rm -rf $shimpath\n    fi\n  fi\n  \n  if [[ ! -f $tool_file_path ]]; then\n    # try to see if the path is lower cased\n    tool_file_path=\"$(echo $tool_file_path | tr \"[:upper:]\" \"[:lower:]\")\" \n    if [[ ! -f $tool_file_path ]]; then\n      Write-PipelineTelemetryError -category 'NativeToolsBootstrap' \"Specified tool file path:'$tool_file_path' does not exist\"\n      return 1\n    fi\n  fi\n\n  local shim_contents=$'#!/usr/bin/env bash\\n'\n  shim_contents+=\"SHIMARGS=\"$'$1\\n'\n  shim_contents+=\"$tool_file_path\"$' $SHIMARGS\\n'\n\n  # Write shim file\n  echo \"$shim_contents\" > $shimpath\n\n  chmod +x $shimpath\n\n  echo \"Finished generating shim '$shimpath'\"\n\n  return $?\n}\n\n"
  },
  {
    "path": "eng/common/native/init-compiler.sh",
    "content": "#!/bin/sh\n#\n# This file detects the C/C++ compiler and exports it to the CC/CXX environment variables\n#\n# NOTE: some scripts source this file and rely on stdout being empty, make sure\n# to not output *anything* here, unless it is an error message that fails the\n# build.\n\nif [ -z \"$build_arch\" ] || [ -z \"$compiler\" ]; then\n  echo \"Usage...\"\n  echo \"build_arch=<ARCH> compiler=<NAME> init-compiler.sh\"\n  echo \"Specify the target architecture.\"\n  echo \"Specify the name of compiler (clang or gcc).\"\n  exit 1\nfi\n\ncase \"$compiler\" in\n    clang*|-clang*|--clang*)\n        # clangx.y or clang-x.y\n        version=\"$(echo \"$compiler\" | tr -d '[:alpha:]-=')\"\n        majorVersion=\"${version%%.*}\"\n\n        # LLVM based on v18 released in early 2024, with two releases per year\n        maxVersion=\"$((18 + ((($(date +%Y) - 2024) * 12 + $(date +%-m) - 3) / 6)))\"\n        compiler=clang\n        ;;\n\n    gcc*|-gcc*|--gcc*)\n        # gccx.y or gcc-x.y\n        version=\"$(echo \"$compiler\" | tr -d '[:alpha:]-=')\"\n        majorVersion=\"${version%%.*}\"\n\n        # GCC based on v14 released in early 2024, with one release per year\n        maxVersion=\"$((14 + ((($(date +%Y) - 2024) * 12 + $(date +%-m) - 3) / 12)))\"\n        compiler=gcc\n        ;;\nesac\n\ncxxCompiler=\"$compiler++\"\n\n# clear the existing CC and CXX from environment\nCC=\nCXX=\nLDFLAGS=\n\nif [ \"$compiler\" = \"gcc\" ]; then cxxCompiler=\"g++\"; fi\n\ncheck_version_exists() {\n    desired_version=-1\n\n    # Set up the environment to be used for building with the desired compiler.\n    if command -v \"$compiler-$1\" > /dev/null; then\n        desired_version=\"-$1\"\n    elif command -v \"$compiler$1\" > /dev/null; then\n        desired_version=\"$1\"\n    fi\n\n    echo \"$desired_version\"\n}\n\n__baseOS=\"$(uname)\"\nset_compiler_version_from_CC() {\n    if [ \"$__baseOS\" = \"Darwin\" ]; then\n        # On Darwin, the versions from -version/-dumpversion refer to Xcode\n        # versions, not llvm versions, so we can't rely on them.\n        return\n    fi\n\n    version=\"$(\"$CC\" -dumpversion)\"\n    if [ -z \"$version\" ]; then\n        echo \"Error: $CC -dumpversion didn't provide a version\"\n        exit 1\n    fi\n\n    # gcc and clang often display 3 part versions. However, gcc can show only 1 part in some environments.\n    IFS=. read -r majorVersion _ <<EOF\n$version\nEOF\n}\n\nif [ -z \"$CLR_CC\" ]; then\n\n    # Set default versions\n    if [ -z \"$majorVersion\" ]; then\n        minVersion=8\n        maxVersion=\"$((maxVersion + 1))\" # +1 for headspace\n        i=\"$maxVersion\"\n        while [ \"$i\" -ge $minVersion ]; do\n            desired_version=\"$(check_version_exists \"$i\")\"\n            if [ \"$desired_version\" != \"-1\" ]; then majorVersion=\"$i\"; break; fi\n            i=$((i - 1))\n        done\n\n        if [ -z \"$majorVersion\" ]; then\n            if ! command -v \"$compiler\" > /dev/null; then\n                echo \"Error: No compatible version of $compiler was found within the range of $minVersion to $maxVersion. Please upgrade your toolchain or specify the compiler explicitly using CLR_CC and CLR_CXX environment variables.\"\n                exit 1\n            fi\n\n            CC=\"$(command -v \"$compiler\" 2> /dev/null)\"\n            CXX=\"$(command -v \"$cxxCompiler\" 2> /dev/null)\"\n            set_compiler_version_from_CC\n        fi\n    else\n        desired_version=\"$(check_version_exists \"$majorVersion\")\"\n        if [ \"$desired_version\" = \"-1\" ]; then\n            echo \"Error: Could not find specific version of $compiler: $majorVersion.\"\n            exit 1\n        fi\n    fi\n\n    if [ -z \"$CC\" ]; then\n        CC=\"$(command -v \"$compiler$desired_version\" 2> /dev/null)\"\n        CXX=\"$(command -v \"$cxxCompiler$desired_version\" 2> /dev/null)\"\n        if [ -z \"$CXX\" ]; then CXX=\"$(command -v \"$cxxCompiler\" 2> /dev/null)\"; fi\n        set_compiler_version_from_CC\n    fi\nelse\n    if [ ! -f \"$CLR_CC\" ]; then\n        echo \"Error: CLR_CC is set but path '$CLR_CC' does not exist\"\n        exit 1\n    fi\n    CC=\"$CLR_CC\"\n    CXX=\"$CLR_CXX\"\n    set_compiler_version_from_CC\nfi\n\nif [ -z \"$CC\" ]; then\n    echo \"Error: Unable to find $compiler.\"\n    exit 1\nfi\n\nif [ \"$__baseOS\" != \"Darwin\" ]; then\n    # On Darwin, we always want to use the Apple linker.\n\n    # Only lld version >= 9 can be considered stable. lld supports s390x starting from 18.0.\n    if [ \"$compiler\" = \"clang\" ] && [ -n \"$majorVersion\" ] && [ \"$majorVersion\" -ge 9 ] && { [ \"$build_arch\" != \"s390x\" ] || [ \"$majorVersion\" -ge 18 ]; }; then\n        if \"$CC\" -fuse-ld=lld -Wl,--version >/dev/null 2>&1; then\n            LDFLAGS=\"-fuse-ld=lld\"\n        fi\n    fi\nfi\n\nSCAN_BUILD_COMMAND=\"$(command -v \"scan-build$desired_version\" 2> /dev/null)\"\n\nexport CC CXX LDFLAGS SCAN_BUILD_COMMAND\n"
  },
  {
    "path": "eng/common/native/init-distro-rid.sh",
    "content": "#!/bin/sh\n\n# getNonPortableDistroRid\n#\n# Input:\n#   targetOs: (str)\n#   targetArch: (str)\n#   rootfsDir: (str)\n#\n# Return:\n#   non-portable rid\ngetNonPortableDistroRid()\n{\n    targetOs=\"$1\"\n    targetArch=\"$2\"\n    rootfsDir=\"$3\"\n    nonPortableRid=\"\"\n\n    if [ \"$targetOs\" = \"linux\" ]; then\n        # shellcheck disable=SC1091\n        if [ -e \"${rootfsDir}/etc/os-release\" ]; then\n            . \"${rootfsDir}/etc/os-release\"\n            if echo \"${VERSION_ID:-}\" | grep -qE '^([[:digit:]]|\\.)+$'; then\n                nonPortableRid=\"${ID}.${VERSION_ID}-${targetArch}\"\n            else\n                # Rolling release distros either do not set VERSION_ID, set it as blank or\n                # set it to non-version looking string (such as TEMPLATE_VERSION_ID on ArchLinux);\n                # so omit it here to be consistent with everything else.\n                nonPortableRid=\"${ID}-${targetArch}\"\n            fi\n        elif [ -e \"${rootfsDir}/android_platform\" ]; then\n            # shellcheck disable=SC1091\n            . \"${rootfsDir}/android_platform\"\n            nonPortableRid=\"$RID\"\n        fi\n    fi\n\n    if [ \"$targetOs\" = \"freebsd\" ]; then\n        # $rootfsDir can be empty. freebsd-version is a shell script and should always work.\n        __freebsd_major_version=$(\"$rootfsDir\"/bin/freebsd-version | cut -d'.' -f1)\n        nonPortableRid=\"freebsd.$__freebsd_major_version-${targetArch}\"\n    elif command -v getprop >/dev/null && getprop ro.product.system.model | grep -qi android; then\n        __android_sdk_version=$(getprop ro.build.version.sdk)\n        nonPortableRid=\"android.$__android_sdk_version-${targetArch}\"\n    elif [ \"$targetOs\" = \"illumos\" ]; then\n        __uname_version=$(uname -v)\n        nonPortableRid=\"illumos-${targetArch}\"\n    elif [ \"$targetOs\" = \"solaris\" ]; then\n        __uname_version=$(uname -v)\n        __solaris_major_version=$(echo \"$__uname_version\" | cut -d'.' -f1)\n        nonPortableRid=\"solaris.$__solaris_major_version-${targetArch}\"\n    elif [ \"$targetOs\" = \"haiku\" ]; then\n        __uname_release=\"$(uname -r)\"\n        nonPortableRid=haiku.r\"$__uname_release\"-\"$targetArch\"\n    fi\n\n    echo \"$nonPortableRid\" | tr '[:upper:]' '[:lower:]'\n}\n\n# initDistroRidGlobal\n#\n# Input:\n#   os: (str)\n#   arch: (str)\n#   rootfsDir?: (nullable:string)\n#\n# Return:\n#   None\n#\n# Notes:\n#   It is important to note that the function does not return anything, but it\n#   exports the following variables on success:\n#     __DistroRid   : Non-portable rid of the target platform.\n#     __PortableTargetOS  : OS-part of the portable rid that corresponds to the target platform.\ninitDistroRidGlobal()\n{\n    targetOs=\"$1\"\n    targetArch=\"$2\"\n    rootfsDir=\"\"\n    if [ $# -ge 3 ]; then\n        rootfsDir=\"$3\"\n    fi\n\n    if [ -n \"${rootfsDir}\" ]; then\n        # We may have a cross build. Check for the existence of the rootfsDir\n        if [ ! -e \"${rootfsDir}\" ]; then\n            echo \"Error: rootfsDir has been passed, but the location is not valid.\"\n            exit 1\n        fi\n    fi\n\n    __DistroRid=$(getNonPortableDistroRid \"${targetOs}\" \"${targetArch}\" \"${rootfsDir}\")\n\n    if [ -z \"${__PortableTargetOS:-}\" ]; then\n        __PortableTargetOS=\"$targetOs\"\n\n        STRINGS=\"$(command -v strings || true)\"\n        if [ -z \"$STRINGS\" ]; then\n            STRINGS=\"$(command -v llvm-strings || true)\"\n        fi\n\n        # Check for musl-based distros (e.g. Alpine Linux, Void Linux).\n        if \"${rootfsDir}/usr/bin/ldd\" --version 2>&1 | grep -q musl ||\n                ( [ -n \"$STRINGS\" ] && \"$STRINGS\" \"${rootfsDir}/usr/bin/ldd\" 2>&1 | grep -q musl ); then\n            __PortableTargetOS=\"linux-musl\"\n        fi\n    fi\n\n    export __DistroRid __PortableTargetOS\n}\n"
  },
  {
    "path": "eng/common/native/init-os-and-arch.sh",
    "content": "#!/bin/sh\n\n# Use uname to determine what the OS is.\nOSName=$(uname -s | tr '[:upper:]' '[:lower:]')\n\nif command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then\n    OSName=\"android\"\nfi\n\ncase \"$OSName\" in\nfreebsd|linux|netbsd|openbsd|sunos|android|haiku)\n    os=\"$OSName\" ;;\ndarwin)\n    os=osx ;;\n*)\n    echo \"Unsupported OS $OSName detected!\"\n    exit 1 ;;\nesac\n\n# On Solaris, `uname -m` is discouraged, see https://docs.oracle.com/cd/E36784_01/html/E36870/uname-1.html\n# and `uname -p` returns processor type (e.g. i386 on amd64).\n# The appropriate tool to determine CPU is isainfo(1) https://docs.oracle.com/cd/E36784_01/html/E36870/isainfo-1.html.\nif [ \"$os\" = \"sunos\" ]; then\n    if uname -o 2>&1 | grep -q illumos; then\n        os=\"illumos\"\n    else\n        os=\"solaris\"\n    fi\n    CPUName=$(isainfo -n)\nelse\n    # For the rest of the operating systems, use uname(1) to determine what the CPU is.\n    CPUName=$(uname -m)\nfi\n\ncase \"$CPUName\" in\n    arm64|aarch64)\n        arch=arm64\n        if [ \"$(getconf LONG_BIT)\" -lt 64 ]; then\n            # This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)\n            arch=arm\n        fi\n        ;;\n\n    loongarch64)\n        arch=loongarch64\n        ;;\n\n    riscv64)\n        arch=riscv64\n        ;;\n\n    amd64|x86_64)\n        arch=x64\n        ;;\n\n    armv7l|armv8l)\n        # shellcheck disable=SC1091\n        if (NAME=\"\"; . /etc/os-release; test \"$NAME\" = \"Tizen\"); then\n            arch=armel\n        else\n            arch=arm\n        fi\n        ;;\n\n    armv6l)\n        arch=armv6\n        ;;\n\n    i[3-6]86)\n        echo \"Unsupported CPU $CPUName detected, build might not succeed!\"\n        arch=x86\n        ;;\n\n    s390x)\n        arch=s390x\n        ;;\n\n    ppc64le)\n        arch=ppc64le\n        ;;\n    *)\n        echo \"Unknown CPU $CPUName detected!\"\n        exit 1\n        ;;\nesac\n"
  },
  {
    "path": "eng/common/native/install-cmake-test.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. $scriptroot/common-library.sh\n\nbase_uri=\ninstall_path=\nversion=\nclean=false\nforce=false\ndownload_retries=5\nretry_wait_time_seconds=30\n\nwhile (($# > 0)); do\n  lowerI=\"$(echo $1 | tr \"[:upper:]\" \"[:lower:]\")\"\n  case $lowerI in\n    --baseuri)\n      base_uri=$2\n      shift 2\n      ;;\n    --installpath)\n      install_path=$2\n      shift 2\n      ;;\n    --version)\n      version=$2\n      shift 2\n      ;;\n    --clean)\n      clean=true\n      shift 1\n      ;;\n    --force)\n      force=true\n      shift 1\n      ;;\n    --downloadretries)\n      download_retries=$2\n      shift 2\n      ;;\n    --retrywaittimeseconds)\n      retry_wait_time_seconds=$2\n      shift 2\n      ;;\n    --help)\n      echo \"Common settings:\"\n      echo \"  --baseuri <value>        Base file directory or Url wrom which to acquire tool archives\"\n      echo \"  --installpath <value>    Base directory to install native tool to\"\n      echo \"  --clean                  Don't install the tool, just clean up the current install of the tool\"\n      echo \"  --force                  Force install of tools even if they previously exist\"\n      echo \"  --help                   Print help and exit\"\n      echo \"\"\n      echo \"Advanced settings:\"\n      echo \"  --downloadretries        Total number of retry attempts\"\n      echo \"  --retrywaittimeseconds   Wait time between retry attempts in seconds\"\n      echo \"\"\n      exit 0\n      ;;\n  esac\ndone\n\ntool_name=\"cmake-test\"\ntool_os=$(GetCurrentOS)\ntool_folder=\"$(echo $tool_os | tr \"[:upper:]\" \"[:lower:]\")\"\ntool_arch=\"x86_64\"\ntool_name_moniker=\"$tool_name-$version-$tool_os-$tool_arch\"\ntool_install_directory=\"$install_path/$tool_name/$version\"\ntool_file_path=\"$tool_install_directory/$tool_name_moniker/bin/$tool_name\"\nshim_path=\"$install_path/$tool_name.sh\"\nuri=\"${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz\"\n\n# Clean up tool and installers\nif [[ $clean = true ]]; then\n  echo \"Cleaning $tool_install_directory\"\n  if [[ -d $tool_install_directory ]]; then\n    rm -rf $tool_install_directory\n  fi\n\n  echo \"Cleaning $shim_path\"\n  if [[ -f $shim_path ]]; then\n    rm -rf $shim_path\n  fi\n\n  tool_temp_path=$(GetTempPathFileName $uri)\n  echo \"Cleaning $tool_temp_path\"\n  if [[ -f $tool_temp_path ]]; then\n    rm -rf $tool_temp_path\n  fi\n\n  exit 0\nfi\n\n# Install tool\nif [[ -f $tool_file_path ]] && [[ $force = false ]]; then\n  echo \"$tool_name ($version) already exists, skipping install\"\n  exit 0\nfi\n\nDownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds\n\nif [[ $? != 0 ]]; then\n  Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'\n  exit 1\nfi\n\n# Generate Shim\n# Always rewrite shims so that we are referencing the expected version\nNewScriptShim $shim_path $tool_file_path true\n\nif [[ $? != 0 ]]; then\n  Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'\n  exit 1\nfi\n\nexit 0\n"
  },
  {
    "path": "eng/common/native/install-cmake.sh",
    "content": "#!/usr/bin/env bash\n\nsource=\"${BASH_SOURCE[0]}\"\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\n. $scriptroot/common-library.sh\n\nbase_uri=\ninstall_path=\nversion=\nclean=false\nforce=false\ndownload_retries=5\nretry_wait_time_seconds=30\n\nwhile (($# > 0)); do\n  lowerI=\"$(echo $1 | tr \"[:upper:]\" \"[:lower:]\")\"\n  case $lowerI in\n    --baseuri)\n      base_uri=$2\n      shift 2\n      ;;\n    --installpath)\n      install_path=$2\n      shift 2\n      ;;\n    --version)\n      version=$2\n      shift 2\n      ;;\n    --clean)\n      clean=true\n      shift 1\n      ;;\n    --force)\n      force=true\n      shift 1\n      ;;\n    --downloadretries)\n      download_retries=$2\n      shift 2\n      ;;\n    --retrywaittimeseconds)\n      retry_wait_time_seconds=$2\n      shift 2\n      ;;\n    --help)\n      echo \"Common settings:\"\n      echo \"  --baseuri <value>        Base file directory or Url wrom which to acquire tool archives\"\n      echo \"  --installpath <value>    Base directory to install native tool to\"\n      echo \"  --clean                  Don't install the tool, just clean up the current install of the tool\"\n      echo \"  --force                  Force install of tools even if they previously exist\"\n      echo \"  --help                   Print help and exit\"\n      echo \"\"\n      echo \"Advanced settings:\"\n      echo \"  --downloadretries        Total number of retry attempts\"\n      echo \"  --retrywaittimeseconds   Wait time between retry attempts in seconds\"\n      echo \"\"\n      exit 0\n      ;;\n  esac\ndone\n\ntool_name=\"cmake\"\ntool_os=$(GetCurrentOS)\ntool_folder=\"$(echo $tool_os | tr \"[:upper:]\" \"[:lower:]\")\"\ntool_arch=\"x86_64\"\ntool_name_moniker=\"$tool_name-$version-$tool_os-$tool_arch\"\ntool_install_directory=\"$install_path/$tool_name/$version\"\ntool_file_path=\"$tool_install_directory/$tool_name_moniker/bin/$tool_name\"\nshim_path=\"$install_path/$tool_name.sh\"\nuri=\"${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz\"\n\n# Clean up tool and installers\nif [[ $clean = true ]]; then\n  echo \"Cleaning $tool_install_directory\"\n  if [[ -d $tool_install_directory ]]; then\n    rm -rf $tool_install_directory\n  fi\n\n  echo \"Cleaning $shim_path\"\n  if [[ -f $shim_path ]]; then\n    rm -rf $shim_path\n  fi\n\n  tool_temp_path=$(GetTempPathFileName $uri)\n  echo \"Cleaning $tool_temp_path\"\n  if [[ -f $tool_temp_path ]]; then\n    rm -rf $tool_temp_path\n  fi\n\n  exit 0\nfi\n\n# Install tool\nif [[ -f $tool_file_path ]] && [[ $force = false ]]; then\n  echo \"$tool_name ($version) already exists, skipping install\"\n  exit 0\nfi\n\nDownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds\n\nif [[ $? != 0 ]]; then\n  Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'\n  exit 1\nfi\n\n# Generate Shim\n# Always rewrite shims so that we are referencing the expected version\nNewScriptShim $shim_path $tool_file_path true\n\nif [[ $? != 0 ]]; then\n  Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'\n  exit 1\nfi\n\nexit 0\n"
  },
  {
    "path": "eng/common/native/install-dependencies.sh",
    "content": "#!/bin/sh\n\nset -e\n\n# This is a simple script primarily used for CI to install necessary dependencies\n#\n# Usage:\n#\n# ./install-dependencies.sh <OS>\n\nos=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n\nif [ -z \"$os\" ]; then\n    . \"$(dirname \"$0\")\"/init-os-and-arch.sh\nfi\n\ncase \"$os\" in\n    linux)\n        if [ -e /etc/os-release ]; then\n            . /etc/os-release\n        fi\n\n        if [ \"$ID\" = \"debian\" ] || [ \"$ID_LIKE\" = \"debian\" ]; then\n            apt update\n\n            apt install -y build-essential gettext locales cmake llvm clang lld lldb liblldb-dev libunwind8-dev libicu-dev liblttng-ust-dev \\\n                libssl-dev libkrb5-dev pigz cpio\n\n            localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8\n        elif [ \"$ID\" = \"fedora\" ] || [ \"$ID\" = \"rhel\" ] || [ \"$ID\" = \"azurelinux\" ]; then\n            pkg_mgr=\"$(command -v tdnf 2>/dev/null || command -v dnf)\"\n            $pkg_mgr install -y cmake llvm lld lldb clang python curl libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio\n        elif [ \"$ID\" = \"alpine\" ]; then\n            apk add build-base cmake bash curl clang llvm-dev lld lldb krb5-dev lttng-ust-dev icu-dev openssl-dev pigz cpio\n        else\n            echo \"Unsupported distro. distro: $ID\"\n            exit 1\n        fi\n        ;;\n\n    osx|maccatalyst|ios|iossimulator|tvos|tvossimulator)\n        echo \"Installed xcode version: $(xcode-select -p)\"\n\n        export HOMEBREW_NO_INSTALL_CLEANUP=1\n        export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1\n        # Skip brew update for now, see https://github.com/actions/setup-python/issues/577\n        # brew update --preinstall\n        brew bundle --no-upgrade --file=- <<EOF\nbrew \"cmake\"\nbrew \"icu4c\"\nbrew \"openssl@3\"\nbrew \"pkgconf\"\nbrew \"python3\"\nbrew \"pigz\"\nEOF\n        ;;\n\n    *)\n        echo \"Unsupported platform. OS: $os\"\n        exit 1\n        ;;\nesac\n"
  },
  {
    "path": "eng/common/native/install-tool.ps1",
    "content": "<#\n.SYNOPSIS\nInstall native tool\n\n.DESCRIPTION\nInstall cmake native tool from Azure blob storage\n\n.PARAMETER InstallPath\nBase directory to install native tool to\n\n.PARAMETER BaseUri\nBase file directory or Url from which to acquire tool archives\n\n.PARAMETER CommonLibraryDirectory\nPath to folder containing common library modules\n\n.PARAMETER Force\nForce install of tools even if they previously exist\n\n.PARAMETER Clean\nDon't install the tool, just clean up the current install of the tool\n\n.PARAMETER DownloadRetries\nTotal number of retry attempts\n\n.PARAMETER RetryWaitTimeInSeconds\nWait time between retry attempts in seconds\n\n.NOTES\nReturns 0 if install succeeds, 1 otherwise\n#>\n[CmdletBinding(PositionalBinding=$false)]\nParam (\n  [Parameter(Mandatory=$True)]\n  [string] $ToolName,\n  [Parameter(Mandatory=$True)]\n  [string] $InstallPath,\n  [Parameter(Mandatory=$True)]\n  [string] $BaseUri,\n  [Parameter(Mandatory=$True)]\n  [string] $Version,\n  [string] $CommonLibraryDirectory = $PSScriptRoot,\n  [switch] $Force = $False,\n  [switch] $Clean = $False,\n  [int] $DownloadRetries = 5,\n  [int] $RetryWaitTimeInSeconds = 30\n)\n\n. $PSScriptRoot\\..\\pipeline-logging-functions.ps1\n\n# Import common library modules\nImport-Module -Name (Join-Path $CommonLibraryDirectory \"CommonLibrary.psm1\")\n\ntry {\n  # Define verbose switch if undefined\n  $Verbose = $VerbosePreference -Eq \"Continue\"\n\n  $Arch = CommonLibrary\\Get-MachineArchitecture\n  $ToolOs = \"win64\"\n  if($Arch -Eq \"x32\") {\n    $ToolOs = \"win32\"\n  }\n  $ToolNameMoniker = \"$ToolName-$Version-$ToolOs-$Arch\"\n  $ToolInstallDirectory = Join-Path $InstallPath \"$ToolName\\$Version\\\"\n  $Uri = \"$BaseUri/windows/$ToolName/$ToolNameMoniker.zip\"\n  $ShimPath = Join-Path $InstallPath \"$ToolName.exe\"\n\n  if ($Clean) {\n    Write-Host \"Cleaning $ToolInstallDirectory\"\n    if (Test-Path $ToolInstallDirectory) {\n      Remove-Item $ToolInstallDirectory -Force -Recurse\n    }\n    Write-Host \"Cleaning $ShimPath\"\n    if (Test-Path $ShimPath) {\n      Remove-Item $ShimPath -Force\n    }\n    $ToolTempPath = CommonLibrary\\Get-TempPathFilename -Path $Uri\n    Write-Host \"Cleaning $ToolTempPath\"\n    if (Test-Path $ToolTempPath) {\n      Remove-Item $ToolTempPath -Force\n    }\n    exit 0\n  }\n\n  # Install tool\n  if ((Test-Path $ToolInstallDirectory) -And (-Not $Force)) {\n    Write-Verbose \"$ToolName ($Version) already exists, skipping install\"\n  }\n  else {\n    $InstallStatus = CommonLibrary\\DownloadAndExtract -Uri $Uri `\n                                                      -InstallDirectory $ToolInstallDirectory `\n                                                      -Force:$Force `\n                                                      -DownloadRetries $DownloadRetries `\n                                                      -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `\n                                                      -Verbose:$Verbose\n\n    if ($InstallStatus -Eq $False) {\n      Write-PipelineTelemetryError \"Installation failed\" -Category \"NativeToolsetBootstrapping\"\n      exit 1\n    }\n  }\n\n  $ToolFilePath = Get-ChildItem $ToolInstallDirectory -Recurse -Filter \"$ToolName.exe\" | % { $_.FullName }\n  if (@($ToolFilePath).Length -Gt 1) {\n    Write-Error \"There are multiple copies of $ToolName in $($ToolInstallDirectory): `n$(@($ToolFilePath | out-string))\"\n    exit 1\n  } elseif (@($ToolFilePath).Length -Lt 1) {\n    Write-Host \"$ToolName was not found in $ToolInstallDirectory.\"\n    exit 1\n  }\n\n  # Generate shim\n  # Always rewrite shims so that we are referencing the expected version\n  $GenerateShimStatus = CommonLibrary\\New-ScriptShim -ShimName $ToolName `\n                                                     -ShimDirectory $InstallPath `\n                                                     -ToolFilePath \"$ToolFilePath\" `\n                                                     -BaseUri $BaseUri `\n                                                     -Force:$Force `\n                                                     -Verbose:$Verbose\n\n  if ($GenerateShimStatus -Eq $False) {\n    Write-PipelineTelemetryError \"Generate shim failed\" -Category \"NativeToolsetBootstrapping\"\n    return 1\n  }\n\n  exit 0\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category \"NativeToolsetBootstrapping\" -Message $_\n  exit 1\n}\n"
  },
  {
    "path": "eng/common/pipeline-logging-functions.ps1",
    "content": "# Source for this file was taken from https://github.com/microsoft/azure-pipelines-task-lib/blob/11c9439d4af17e6475d9fe058e6b2e03914d17e6/powershell/VstsTaskSdk/LoggingCommandFunctions.ps1 and modified.\n\n# NOTE: You should not be calling these method directly as they are likely to change.  Instead you should be calling the Write-Pipeline* functions defined in tools.ps1\n\n$script:loggingCommandPrefix = '##vso['\n$script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT \"=\"? WHAT ABOUT \"%\"?\n    New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' }\n    New-Object psobject -Property @{ Token = \"`r\" ; Replacement = '%0D' }\n    New-Object psobject -Property @{ Token = \"`n\" ; Replacement = '%0A' }\n    New-Object psobject -Property @{ Token = \"]\" ; Replacement = '%5D' }\n)\n# TODO: BUG: Escape % ???\n# TODO: Add test to verify don't need to escape \"=\".\n\n# Specify \"-Force\" to force pipeline formatted output even if \"$ci\" is false or not set\nfunction Write-PipelineTelemetryError {\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$Category,\n        [Parameter(Mandatory = $true)]\n        [string]$Message,\n        [Parameter(Mandatory = $false)]\n        [string]$Type = 'error',\n        [string]$ErrCode,\n        [string]$SourcePath,\n        [string]$LineNumber,\n        [string]$ColumnNumber,\n        [switch]$AsOutput,\n        [switch]$Force)\n\n    $PSBoundParameters.Remove('Category') | Out-Null\n\n    if ($Force -Or ((Test-Path variable:ci) -And $ci)) {\n        $Message = \"(NETCORE_ENGINEERING_TELEMETRY=$Category) $Message\"\n    }\n    $PSBoundParameters.Remove('Message') | Out-Null\n    $PSBoundParameters.Add('Message', $Message)\n    Write-PipelineTaskError @PSBoundParameters\n}\n\n# Specify \"-Force\" to force pipeline formatted output even if \"$ci\" is false or not set\nfunction Write-PipelineTaskError {\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$Message,\n        [Parameter(Mandatory = $false)]\n        [string]$Type = 'error',\n        [string]$ErrCode,\n        [string]$SourcePath,\n        [string]$LineNumber,\n        [string]$ColumnNumber,\n        [switch]$AsOutput,\n        [switch]$Force\n    )\n\n    if (!$Force -And (-Not (Test-Path variable:ci) -Or !$ci)) {\n        if ($Type -eq 'error') {\n            Write-Host $Message -ForegroundColor Red\n            return\n        }\n        elseif ($Type -eq 'warning') {\n            Write-Host $Message -ForegroundColor Yellow\n            return\n        }\n    }\n\n    if (($Type -ne 'error') -and ($Type -ne 'warning')) {\n        Write-Host $Message\n        return\n    }\n    $PSBoundParameters.Remove('Force') | Out-Null      \n    if (-not $PSBoundParameters.ContainsKey('Type')) {\n        $PSBoundParameters.Add('Type', 'error')\n    }\n    Write-LogIssue @PSBoundParameters\n}\n  \nfunction Write-PipelineSetVariable {\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$Name,\n        [string]$Value,\n        [switch]$Secret,\n        [switch]$AsOutput,\n        [bool]$IsMultiJobVariable = $true)\n\n    if ((Test-Path variable:ci) -And $ci) {\n        Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{\n            'variable' = $Name\n            'isSecret' = $Secret\n            'isOutput' = $IsMultiJobVariable\n        } -AsOutput:$AsOutput\n    }\n}\n  \nfunction Write-PipelinePrependPath {\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$Path,\n        [switch]$AsOutput)\n\n    if ((Test-Path variable:ci) -And $ci) {\n        Write-LoggingCommand -Area 'task' -Event 'prependpath' -Data $Path -AsOutput:$AsOutput\n    }\n}\n\nfunction Write-PipelineSetResult {\n    [CmdletBinding()]\n    param(\n        [ValidateSet(\"Succeeded\", \"SucceededWithIssues\", \"Failed\", \"Cancelled\", \"Skipped\")]\n        [Parameter(Mandatory = $true)]\n        [string]$Result,\n        [string]$Message)\n    if ((Test-Path variable:ci) -And $ci) {\n        Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{\n            'result' = $Result\n        }\n    }\n}\n\n<########################################\n# Private functions.\n########################################>\nfunction Format-LoggingCommandData {\n    [CmdletBinding()]\n    param([string]$Value, [switch]$Reverse)\n\n    if (!$Value) {\n        return ''\n    }\n\n    if (!$Reverse) {\n        foreach ($mapping in $script:loggingCommandEscapeMappings) {\n            $Value = $Value.Replace($mapping.Token, $mapping.Replacement)\n        }\n    }\n    else {\n        for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) {\n            $mapping = $script:loggingCommandEscapeMappings[$i]\n            $Value = $Value.Replace($mapping.Replacement, $mapping.Token)\n        }\n    }\n\n    return $Value\n}\n\nfunction Format-LoggingCommand {\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$Area,\n        [Parameter(Mandatory = $true)]\n        [string]$Event,\n        [string]$Data,\n        [hashtable]$Properties)\n\n    # Append the preamble.\n    [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder\n    $null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event)\n\n    # Append the properties.\n    if ($Properties) {\n        $first = $true\n        foreach ($key in $Properties.Keys) {\n            [string]$value = Format-LoggingCommandData $Properties[$key]\n            if ($value) {\n                if ($first) {\n                    $null = $sb.Append(' ')\n                    $first = $false\n                }\n                else {\n                    $null = $sb.Append(';')\n                }\n\n                $null = $sb.Append(\"$key=$value\")\n            }\n        }\n    }\n\n    # Append the tail and output the value.\n    $Data = Format-LoggingCommandData $Data\n    $sb.Append(']').Append($Data).ToString()\n}\n\nfunction Write-LoggingCommand {\n    [CmdletBinding(DefaultParameterSetName = 'Parameters')]\n    param(\n        [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]\n        [string]$Area,\n        [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]\n        [string]$Event,\n        [Parameter(ParameterSetName = 'Parameters')]\n        [string]$Data,\n        [Parameter(ParameterSetName = 'Parameters')]\n        [hashtable]$Properties,\n        [Parameter(Mandatory = $true, ParameterSetName = 'Object')]\n        $Command,\n        [switch]$AsOutput)\n\n    if ($PSCmdlet.ParameterSetName -eq 'Object') {\n        Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput\n        return\n    }\n\n    $command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties\n    if ($AsOutput) {\n        $command\n    }\n    else {\n        Write-Host $command\n    }\n}\n\nfunction Write-LogIssue {\n    [CmdletBinding()]\n    param(\n        [ValidateSet('warning', 'error')]\n        [Parameter(Mandatory = $true)]\n        [string]$Type,\n        [string]$Message,\n        [string]$ErrCode,\n        [string]$SourcePath,\n        [string]$LineNumber,\n        [string]$ColumnNumber,\n        [switch]$AsOutput)\n\n    $command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{\n        'type'         = $Type\n        'code'         = $ErrCode\n        'sourcepath'   = $SourcePath\n        'linenumber'   = $LineNumber\n        'columnnumber' = $ColumnNumber\n    }\n    if ($AsOutput) {\n        return $command\n    }\n\n    if ($Type -eq 'error') {\n        $foregroundColor = $host.PrivateData.ErrorForegroundColor\n        $backgroundColor = $host.PrivateData.ErrorBackgroundColor\n        if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {\n            $foregroundColor = [System.ConsoleColor]::Red\n            $backgroundColor = [System.ConsoleColor]::Black\n        }\n    }\n    else {\n        $foregroundColor = $host.PrivateData.WarningForegroundColor\n        $backgroundColor = $host.PrivateData.WarningBackgroundColor\n        if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {\n            $foregroundColor = [System.ConsoleColor]::Yellow\n            $backgroundColor = [System.ConsoleColor]::Black\n        }\n    }\n\n    Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor\n}\n"
  },
  {
    "path": "eng/common/pipeline-logging-functions.sh",
    "content": "#!/usr/bin/env bash\n\nfunction Write-PipelineTelemetryError {\n  local telemetry_category=''\n  local force=false\n  local function_args=()\n  local message=''\n  while [[ $# -gt 0 ]]; do\n    opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case \"$opt\" in\n      -category|-c)\n        telemetry_category=$2\n        shift\n        ;;\n      -force|-f)\n        force=true\n        ;;\n      -*)\n        function_args+=(\"$1 $2\")\n        shift\n        ;;\n      *)\n        message=$*\n        ;;\n    esac\n    shift\n  done\n\n  if [[ $force != true ]] && [[ \"$ci\" != true ]]; then\n    echo \"$message\" >&2\n    return\n  fi\n\n  if [[ $force == true ]]; then\n    function_args+=(\"-force\")\n  fi\n  message=\"(NETCORE_ENGINEERING_TELEMETRY=$telemetry_category) $message\"\n  function_args+=(\"$message\")\n  Write-PipelineTaskError ${function_args[@]}\n}\n\nfunction Write-PipelineTaskError {\n  local message_type=\"error\"\n  local sourcepath=''\n  local linenumber=''\n  local columnnumber=''\n  local error_code=''\n  local force=false\n\n  while [[ $# -gt 0 ]]; do\n    opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case \"$opt\" in\n      -type|-t)\n        message_type=$2\n        shift\n        ;;\n      -sourcepath|-s)\n        sourcepath=$2\n        shift\n        ;;\n      -linenumber|-ln)\n        linenumber=$2\n        shift\n        ;;\n      -columnnumber|-cn)\n        columnnumber=$2\n        shift\n        ;;\n      -errcode|-e)\n        error_code=$2\n        shift\n        ;;\n      -force|-f)\n        force=true\n        ;;\n      *)\n        break\n        ;;\n    esac\n\n    shift\n  done\n\n  if [[ $force != true ]] && [[ \"$ci\" != true ]]; then\n    echo \"$@\" >&2\n    return\n  fi\n\n  local message=\"##vso[task.logissue\"\n\n  message=\"$message type=$message_type\"\n\n  if [ -n \"$sourcepath\" ]; then\n    message=\"$message;sourcepath=$sourcepath\"\n  fi\n\n  if [ -n \"$linenumber\" ]; then\n    message=\"$message;linenumber=$linenumber\"\n  fi\n\n  if [ -n \"$columnnumber\" ]; then\n    message=\"$message;columnnumber=$columnnumber\"\n  fi\n\n  if [ -n \"$error_code\" ]; then\n    message=\"$message;code=$error_code\"\n  fi\n\n  message=\"$message]$*\"\n  echo \"$message\"\n}\n\nfunction Write-PipelineSetVariable {\n  if [[ \"$ci\" != true ]]; then\n    return\n  fi\n\n  local name=''\n  local value=''\n  local secret=false\n  local as_output=false\n  local is_multi_job_variable=true\n\n  while [[ $# -gt 0 ]]; do\n    opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case \"$opt\" in\n      -name|-n)\n        name=$2\n        shift\n        ;;\n      -value|-v)\n        value=$2\n        shift\n        ;;\n      -secret|-s)\n        secret=true\n        ;;\n      -as_output|-a)\n        as_output=true\n        ;;\n      -is_multi_job_variable|-i)\n        is_multi_job_variable=$2\n        shift\n        ;;\n    esac\n    shift\n  done\n\n  value=${value/;/%3B}\n  value=${value/\\\\r/%0D}\n  value=${value/\\\\n/%0A}\n  value=${value/]/%5D}\n\n  local message=\"##vso[task.setvariable variable=$name;isSecret=$secret;isOutput=$is_multi_job_variable]$value\"\n\n  if [[ \"$as_output\" == true ]]; then\n    $message\n  else\n    echo \"$message\"\n  fi\n}\n\nfunction Write-PipelinePrependPath {\n  local prepend_path=''\n\n  while [[ $# -gt 0 ]]; do\n    opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case \"$opt\" in\n      -path|-p)\n        prepend_path=$2\n        shift\n        ;;\n    esac\n    shift\n  done\n\n  export PATH=\"$prepend_path:$PATH\"\n\n  if [[ \"$ci\" == true ]]; then\n    echo \"##vso[task.prependpath]$prepend_path\"\n  fi\n}\n\nfunction Write-PipelineSetResult {\n  local result=''\n  local message=''\n\n  while [[ $# -gt 0 ]]; do\n    opt=\"$(echo \"${1/#--/-}\" | tr \"[:upper:]\" \"[:lower:]\")\"\n    case \"$opt\" in\n      -result|-r)\n        result=$2\n        shift\n        ;;\n      -message|-m)\n        message=$2\n        shift\n        ;;\n    esac\n    shift\n  done\n\n  if [[ \"$ci\" == true ]]; then\n    echo \"##vso[task.complete result=$result;]$message\"\n  fi\n}\n"
  },
  {
    "path": "eng/common/post-build/check-channel-consistency.ps1",
    "content": "param(\n  [Parameter(Mandatory=$true)][string] $PromoteToChannels,            # List of channels that the build should be promoted to\n  [Parameter(Mandatory=$true)][array] $AvailableChannelIds            # List of channel IDs available in the YAML implementation\n)\n\ntry {\n  $ErrorActionPreference = 'Stop'\n  Set-StrictMode -Version 2.0\n\n  # `tools.ps1` checks $ci to perform some actions. Since the post-build\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  $disableConfigureToolsetImport = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  if ($PromoteToChannels -eq \"\") {\n    Write-PipelineTaskError -Type 'warning' -Message \"This build won't publish assets as it's not configured to any Maestro channel. If that wasn't intended use Darc to configure a default channel using add-default-channel for this branch or to promote it to a channel using add-build-to-channel. See https://github.com/dotnet/arcade/blob/main/Documentation/Darc.md#assigning-an-individual-build-to-a-channel for more info.\"\n    ExitWithExitCode 0\n  }\n\n  # Check that every channel that Maestro told to promote the build to \n  # is available in YAML\n  $PromoteToChannelsIds = $PromoteToChannels -split \"\\D\" | Where-Object { $_ }\n\n  $hasErrors = $false\n\n  foreach ($id in $PromoteToChannelsIds) {\n    if (($id -ne 0) -and ($id -notin $AvailableChannelIds)) {\n      Write-PipelineTaskError -Message \"Channel $id is not present in the post-build YAML configuration! This is an error scenario. Please contact @dnceng.\"\n      $hasErrors = $true\n    }\n  }\n\n  # The `Write-PipelineTaskError` doesn't error the script and we might report several errors\n  # in the previous lines. The check below makes sure that we return an error state from the\n  # script if we reported any validation error\n  if ($hasErrors) {\n    ExitWithExitCode 1 \n  }\n\n  Write-Host 'done.'\n} \ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Category 'CheckChannelConsistency' -Message \"There was an error while trying to check consistency of Maestro default channels for the build and post-build YAML configuration.\"\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/post-build/nuget-validation.ps1",
    "content": "# This script validates NuGet package metadata information using this \n# tool: https://github.com/NuGet/NuGetGallery/tree/jver-verify/src/VerifyMicrosoftPackage\n\nparam(\n  [Parameter(Mandatory=$true)][string] $PackagesPath # Path to where the packages to be validated are\n)\n\n# `tools.ps1` checks $ci to perform some actions. Since the post-build\n# scripts don't necessarily execute in the same agent that run the\n# build.ps1/sh script this variable isn't automatically set.\n$ci = $true\n$disableConfigureToolsetImport = $true\n. $PSScriptRoot\\..\\tools.ps1\n\ntry {\n  & $PSScriptRoot\\nuget-verification.ps1 ${PackagesPath}\\*.nupkg\n} \ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'NuGetValidation' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/post-build/nuget-verification.ps1",
    "content": "<#\n.SYNOPSIS\n    Verifies that Microsoft NuGet packages have proper metadata.\n.DESCRIPTION\n    Downloads a verification tool and runs metadata validation on the provided NuGet packages. This script writes an\n    error if any of the provided packages fail validation. All arguments provided to this PowerShell script that do not\n    match PowerShell parameters are passed on to the verification tool downloaded during the execution of this script.\n.PARAMETER NuGetExePath\n    The path to the nuget.exe binary to use. If not provided, nuget.exe will be downloaded into the -DownloadPath\n    directory.\n.PARAMETER PackageSource\n    The package source to use to download the verification tool. If not provided, nuget.org will be used.\n.PARAMETER DownloadPath\n    The directory path to download the verification tool and nuget.exe to. If not provided,\n    %TEMP%\\NuGet.VerifyNuGetPackage will be used.\n.PARAMETER args\n    Arguments that will be passed to the verification tool.\n.EXAMPLE\n    PS> .\\verify.ps1 *.nupkg\n    Verifies the metadata of all .nupkg files in the currect working directory.\n.EXAMPLE\n    PS> .\\verify.ps1 --help\n    Displays the help text of the downloaded verifiction tool.\n.LINK\n    https://github.com/NuGet/NuGetGallery/blob/master/src/VerifyMicrosoftPackage/README.md\n#>\n\n# This script was copied from https://github.com/NuGet/NuGetGallery/blob/3e25ad135146676bcab0050a516939d9958bfa5d/src/VerifyMicrosoftPackage/verify.ps1\n\n[CmdletBinding(PositionalBinding = $false)]\nparam(\n   [string]$NuGetExePath,\n   [string]$PackageSource = \"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json\",\n   [string]$DownloadPath,\n   [Parameter(ValueFromRemainingArguments = $true)]\n   [string[]]$args\n)\n\n# The URL to download nuget.exe.\n$nugetExeUrl = \"https://dist.nuget.org/win-x86-commandline/v4.9.4/nuget.exe\"\n\n# The package ID of the verification tool.\n$packageId = \"NuGet.VerifyMicrosoftPackage\"\n\n# The location that nuget.exe and the verification tool will be downloaded to.\nif (!$DownloadPath) {\n    $DownloadPath = (Join-Path $env:TEMP \"NuGet.VerifyMicrosoftPackage\")\n}\n\n$fence = New-Object -TypeName string -ArgumentList '=', 80\n\n# Create the download directory, if it doesn't already exist.\nif (!(Test-Path $DownloadPath)) {\n    New-Item -ItemType Directory $DownloadPath | Out-Null\n}\nWrite-Host \"Using download path: $DownloadPath\"\n\nif ($NuGetExePath) {\n    $nuget = $NuGetExePath\n} else {\n    $downloadedNuGetExe = Join-Path $DownloadPath \"nuget.exe\"\n    \n    # Download nuget.exe, if it doesn't already exist.\n    if (!(Test-Path $downloadedNuGetExe)) {\n        Write-Host \"Downloading nuget.exe from $nugetExeUrl...\"\n        $ProgressPreference = 'SilentlyContinue'\n        try {\n            Invoke-WebRequest $nugetExeUrl -UseBasicParsing -OutFile $downloadedNuGetExe\n            $ProgressPreference = 'Continue'\n        } catch {\n            $ProgressPreference = 'Continue'\n            Write-Error $_\n            Write-Error \"nuget.exe failed to download.\"\n            exit\n        }\n    }\n\n    $nuget = $downloadedNuGetExe\n}\n\nWrite-Host \"Using nuget.exe path: $nuget\"\nWrite-Host \" \"\n\n# Download the latest version of the verification tool.\nWrite-Host \"Downloading the latest version of $packageId from $packageSource...\"\nWrite-Host $fence\n& $nuget install $packageId `\n    -Prerelease `\n    -OutputDirectory $DownloadPath `\n    -Source $PackageSource\nWrite-Host $fence\nWrite-Host \" \"\n\nif ($LASTEXITCODE -ne 0) {\n    Write-Error \"nuget.exe failed to fetch the verify tool.\"\n    exit\n}\n\n# Find the most recently downloaded tool\nWrite-Host \"Finding the most recently downloaded verification tool.\"\n$verifyProbePath = Join-Path $DownloadPath \"$packageId.*\"\n$verifyPath = Get-ChildItem -Path $verifyProbePath -Directory `\n    | Sort-Object -Property LastWriteTime -Descending `\n    | Select-Object -First 1\n$verify = Join-Path $verifyPath \"tools\\NuGet.VerifyMicrosoftPackage.exe\"\nWrite-Host \"Using verification tool: $verify\"\nWrite-Host \" \"\n\n# Execute the verification tool.\nWrite-Host \"Executing the verify tool...\"\nWrite-Host $fence\n& $verify $args\nWrite-Host $fence\nWrite-Host \" \"\n\n# Respond to the exit code.\nif ($LASTEXITCODE -ne 0) {\n    Write-Error \"The verify tool found some problems.\"\n} else {\n    Write-Output \"The verify tool succeeded.\"\n}\n"
  },
  {
    "path": "eng/common/post-build/publish-using-darc.ps1",
    "content": "param(\n  [Parameter(Mandatory=$true)][int] $BuildId,\n  [Parameter(Mandatory=$true)][int] $PublishingInfraVersion,\n  [Parameter(Mandatory=$true)][string] $AzdoToken,\n  [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net',\n  [Parameter(Mandatory=$true)][string] $WaitPublishingFinish,\n  [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,\n  [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters,\n  [Parameter(Mandatory=$false)][string] $RequireDefaultChannels,\n  [Parameter(Mandatory=$false)][string] $SkipAssetsPublishing,\n  [Parameter(Mandatory=$false)][string] $runtimeSourceFeed,\n  [Parameter(Mandatory=$false)][string] $runtimeSourceFeedKey\n)\n\ntry {\n  # `tools.ps1` checks $ci to perform some actions. Since the post-build\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  $disableConfigureToolsetImport = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  $darc = Get-Darc\n\n  $optionalParams = [System.Collections.ArrayList]::new()\n\n  if (\"\" -ne $ArtifactsPublishingAdditionalParameters) {\n    $optionalParams.Add(\"--artifact-publishing-parameters\") | Out-Null\n    $optionalParams.Add($ArtifactsPublishingAdditionalParameters) | Out-Null\n  }\n\n  if (\"\" -ne $SymbolPublishingAdditionalParameters) {\n    $optionalParams.Add(\"--symbol-publishing-parameters\") | Out-Null\n    $optionalParams.Add($SymbolPublishingAdditionalParameters) | Out-Null\n  }\n\n  if (\"false\" -eq $WaitPublishingFinish) {\n    $optionalParams.Add(\"--no-wait\") | Out-Null\n  }\n  \n  if (\"true\" -eq $RequireDefaultChannels) {\n    $optionalParams.Add(\"--default-channels-required\") | Out-Null\n  }\n\n  if (\"true\" -eq $SkipAssetsPublishing) {\n    $optionalParams.Add(\"--skip-assets-publishing\") | Out-Null\n  }\n\n  & $darc add-build-to-channel `\n    --id $buildId `\n    --publishing-infra-version $PublishingInfraVersion `\n    --default-channels `\n    --source-branch main `\n    --azdev-pat \"$AzdoToken\" `\n    --bar-uri \"$MaestroApiEndPoint\" `\n    --ci `\n    --verbose `\n\t@optionalParams\n\n  if ($LastExitCode -ne 0) {\n    Write-Host \"Problems using Darc to promote build ${buildId} to default channels. Stopping execution...\"\n    exit 1\n  }\n\n  Write-Host 'done.'\n}\ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Category 'PromoteBuild' -Message \"There was an error while trying to publish build '$BuildId' to default channels.\"\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/post-build/redact-logs.ps1",
    "content": "[CmdletBinding(PositionalBinding=$False)]\nparam(\n  [Parameter(Mandatory=$true, Position=0)][string] $InputPath,\n  [Parameter(Mandatory=$true)][string] $BinlogToolVersion,\n  [Parameter(Mandatory=$false)][string] $DotnetPath,\n  [Parameter(Mandatory=$false)][string] $PackageFeed = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json',\n  # File with strings to redact - separated by newlines.\n  #  For comments start the line with '# ' - such lines are ignored \n  [Parameter(Mandatory=$false)][string] $TokensFilePath,\n  [Parameter(ValueFromRemainingArguments=$true)][String[]]$TokensToRedact,\n  [Parameter(Mandatory=$false)][string] $runtimeSourceFeed,\n  [Parameter(Mandatory=$false)][string] $runtimeSourceFeedKey)\n\ntry {\n  $ErrorActionPreference = 'Stop'\n  Set-StrictMode -Version 2.0\n\n  # `tools.ps1` checks $ci to perform some actions. Since the post-build\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  $disableConfigureToolsetImport = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  $packageName = 'binlogtool'\n\n  $dotnet = $DotnetPath\n\n  if (!$dotnet) {\n    $dotnetRoot = InitializeDotNetCli -install:$true\n    $dotnet = \"$dotnetRoot\\dotnet.exe\"\n  }\n  \n  $toolList = & \"$dotnet\" tool list -g\n\n  if ($toolList -like \"*$packageName*\") {\n    & \"$dotnet\" tool uninstall $packageName -g\n  }\n\n  $toolPath  = \"$PSScriptRoot\\..\\..\\..\\.tools\"\n  $verbosity = 'minimal'\n  \n  New-Item -ItemType Directory -Force -Path $toolPath\n  \n  Push-Location -Path $toolPath\n\n  try {\n    Write-Host \"Installing Binlog redactor CLI...\"\n    Write-Host \"'$dotnet' new tool-manifest\"\n    & \"$dotnet\" new tool-manifest\n    Write-Host \"'$dotnet' tool install $packageName --local --add-source '$PackageFeed' -v $verbosity --version $BinlogToolVersion\"\n    & \"$dotnet\" tool install $packageName --local --add-source \"$PackageFeed\" -v $verbosity --version $BinlogToolVersion\n\n    if (Test-Path $TokensFilePath) {\n        Write-Host \"Adding additional sensitive data for redaction from file: \" $TokensFilePath\n        $TokensToRedact += Get-Content -Path $TokensFilePath | Foreach {$_.Trim()} | Where { $_ -notmatch \"^# \" }\n    }\n\n    $optionalParams = [System.Collections.ArrayList]::new()\n  \n    Foreach ($p in $TokensToRedact)\n    {\n      if($p -match '^\\$\\(.*\\)$')\n      {\n        Write-Host (\"Ignoring token {0} as it is probably unexpanded AzDO variable\"  -f $p)\n      }          \n      elseif($p)\n      {\n        $optionalParams.Add(\"-p:\" + $p) | Out-Null\n      }\n    }\n\n    & $dotnet binlogtool redact --input:$InputPath --recurse --in-place `\n      @optionalParams\n\n    if ($LastExitCode -ne 0) {\n      Write-PipelineTelemetryError -Category 'Redactor' -Type 'warning' -Message \"Problems using Redactor tool (exit code: $LastExitCode). But ignoring them now.\"\n    }\n  }\n  finally {\n    Pop-Location\n  }\n\n  Write-Host 'done.'\n} \ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Category 'Redactor' -Message \"There was an error while trying to redact logs. Error: $_\"\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/post-build/sourcelink-validation.ps1",
    "content": "param(\n  [Parameter(Mandatory=$true)][string] $InputPath,              # Full path to directory where Symbols.NuGet packages to be checked are stored\n  [Parameter(Mandatory=$true)][string] $ExtractPath,            # Full path to directory where the packages will be extracted during validation\n  [Parameter(Mandatory=$false)][string] $GHRepoName,            # GitHub name of the repo including the Org. E.g., dotnet/arcade\n  [Parameter(Mandatory=$false)][string] $GHCommit,              # GitHub commit SHA used to build the packages\n  [Parameter(Mandatory=$true)][string] $SourcelinkCliVersion    # Version of SourceLink CLI to use\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n\n# `tools.ps1` checks $ci to perform some actions. Since the post-build\n# scripts don't necessarily execute in the same agent that run the\n# build.ps1/sh script this variable isn't automatically set.\n$ci = $true\n$disableConfigureToolsetImport = $true\n. $PSScriptRoot\\..\\tools.ps1\n\n# Cache/HashMap (File -> Exist flag) used to consult whether a file exist \n# in the repository at a specific commit point. This is populated by inserting\n# all files present in the repo at a specific commit point.\n$global:RepoFiles = @{}\n\n# Maximum number of jobs to run in parallel\n$MaxParallelJobs = 16\n\n$MaxRetries = 5\n$RetryWaitTimeInSeconds = 30\n\n# Wait time between check for system load\n$SecondsBetweenLoadChecks = 10\n\nif (!$InputPath -or !(Test-Path $InputPath)){\n  Write-Host \"No files to validate.\"\n  ExitWithExitCode 0\n}\n\n$ValidatePackage = {\n  param( \n    [string] $PackagePath                                 # Full path to a Symbols.NuGet package\n  )\n\n  . $using:PSScriptRoot\\..\\tools.ps1\n\n  # Ensure input file exist\n  if (!(Test-Path $PackagePath)) {\n    Write-Host \"Input file does not exist: $PackagePath\"\n    return [pscustomobject]@{\n      result = 1\n      packagePath = $PackagePath\n    }\n  }\n\n  # Extensions for which we'll look for SourceLink information\n  # For now we'll only care about Portable & Embedded PDBs\n  $RelevantExtensions = @('.dll', '.exe', '.pdb')\n \n  Write-Host -NoNewLine 'Validating ' ([System.IO.Path]::GetFileName($PackagePath)) '...'\n\n  $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)\n  $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId\n  $FailedFiles = 0\n\n  Add-Type -AssemblyName System.IO.Compression.FileSystem\n\n  [System.IO.Directory]::CreateDirectory($ExtractPath)  | Out-Null\n\n  try {\n    $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)\n\n    $zip.Entries | \n      Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |\n        ForEach-Object {\n          $FileName = $_.FullName\n          $Extension = [System.IO.Path]::GetExtension($_.Name)\n          $FakeName = -Join((New-Guid), $Extension)\n          $TargetFile = Join-Path -Path $ExtractPath -ChildPath $FakeName \n\n          # We ignore resource DLLs\n          if ($FileName.EndsWith('.resources.dll')) {\n            return [pscustomobject]@{\n              result = 0\n              packagePath = $PackagePath\n            }\n          }\n\n          [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)\n\n          $ValidateFile = {\n            param( \n              [string] $FullPath,                                # Full path to the module that has to be checked\n              [string] $RealPath,\n              [ref] $FailedFiles\n            )\n\n            $sourcelinkExe = \"$env:USERPROFILE\\.dotnet\\tools\"\n            $sourcelinkExe = Resolve-Path \"$sourcelinkExe\\sourcelink.exe\"\n            $SourceLinkInfos = & $sourcelinkExe print-urls $FullPath | Out-String\n\n            if ($LASTEXITCODE -eq 0 -and -not ([string]::IsNullOrEmpty($SourceLinkInfos))) {\n              $NumFailedLinks = 0\n\n              # We only care about Http addresses\n              $Matches = (Select-String '(http[s]?)(:\\/\\/)([^\\s,]+)' -Input $SourceLinkInfos -AllMatches).Matches\n\n              if ($Matches.Count -ne 0) {\n                $Matches.Value |\n                  ForEach-Object {\n                    $Link = $_\n                    $CommitUrl = \"https://raw.githubusercontent.com/${using:GHRepoName}/${using:GHCommit}/\"\n                    \n                    $FilePath = $Link.Replace($CommitUrl, \"\")\n                    $Status = 200\n                    $Cache = $using:RepoFiles\n\n                    $attempts = 0\n\n                    while ($attempts -lt $using:MaxRetries) {\n                      if ( !($Cache.ContainsKey($FilePath)) ) {\n                        try {\n                          $Uri = $Link -as [System.URI]\n                        \n                          if ($Link -match \"submodules\") {\n                            # Skip submodule links until sourcelink properly handles submodules\n                            $Status = 200\n                          }\n                          elseif ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) {\n                            # Only GitHub links are valid\n                            $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode\n                          }\n                          else {\n                            # If it's not a github link, we want to break out of the loop and not retry.\n                            $Status = 0\n                            $attempts = $using:MaxRetries\n                          }\n                        }\n                        catch {\n                          Write-Host $_\n                          $Status = 0\n                        }\n                      }\n\n                      if ($Status -ne 200) {\n                        $attempts++\n                        \n                        if  ($attempts -lt $using:MaxRetries)\n                        {\n                          $attemptsLeft = $using:MaxRetries - $attempts\n                          Write-Warning \"Download failed, $attemptsLeft attempts remaining, will retry in $using:RetryWaitTimeInSeconds seconds\"\n                          Start-Sleep -Seconds $using:RetryWaitTimeInSeconds\n                        }\n                        else {\n                          if ($NumFailedLinks -eq 0) {\n                            if ($FailedFiles.Value -eq 0) {\n                              Write-Host\n                            }\n  \n                            Write-Host \"`tFile $RealPath has broken links:\"\n                          }\n  \n                          Write-Host \"`t`tFailed to retrieve $Link\"\n  \n                          $NumFailedLinks++\n                        }\n                      }\n                      else {\n                        break\n                      }\n                    }\n                  }\n              }\n\n              if ($NumFailedLinks -ne 0) {\n                $FailedFiles.value++\n                $global:LASTEXITCODE = 1\n              }\n            }\n          }\n        \n          &$ValidateFile $TargetFile $FileName ([ref]$FailedFiles)\n        }\n  }\n  catch {\n    Write-Host $_\n  }\n  finally {\n    $zip.Dispose() \n  }\n\n  if ($FailedFiles -eq 0) {\n    Write-Host 'Passed.'\n    return [pscustomobject]@{\n      result = 0\n      packagePath = $PackagePath\n    }\n  }\n  else {\n    Write-PipelineTelemetryError -Category 'SourceLink' -Message \"$PackagePath has broken SourceLink links.\"\n    return [pscustomobject]@{\n      result = 1\n      packagePath = $PackagePath\n    }\n  }\n}\n\nfunction CheckJobResult(\n    $result, \n    $packagePath,\n    [ref]$ValidationFailures,\n    [switch]$logErrors) {\n  if ($result -ne '0') {\n    if ($logErrors) {\n      Write-PipelineTelemetryError -Category 'SourceLink' -Message \"$packagePath has broken SourceLink links.\"\n    }\n    $ValidationFailures.Value++\n  }\n}\n\nfunction ValidateSourceLinkLinks {\n  if ($GHRepoName -ne '' -and !($GHRepoName -Match '^[^\\s\\/]+/[^\\s\\/]+$')) {\n    if (!($GHRepoName -Match '^[^\\s-]+-[^\\s]+$')) {\n      Write-PipelineTelemetryError -Category 'SourceLink' -Message \"GHRepoName should be in the format <org>/<repo> or <org>-<repo>. '$GHRepoName'\"\n      ExitWithExitCode 1\n    }\n    else {\n      $GHRepoName = $GHRepoName -replace '^([^\\s-]+)-([^\\s]+)$', '$1/$2';\n    }\n  }\n\n  if ($GHCommit -ne '' -and !($GHCommit -Match '^[0-9a-fA-F]{40}$')) {\n    Write-PipelineTelemetryError -Category 'SourceLink' -Message \"GHCommit should be a 40 chars hexadecimal string. '$GHCommit'\"\n    ExitWithExitCode 1\n  }\n\n  if ($GHRepoName -ne '' -and $GHCommit -ne '') {\n    $RepoTreeURL = -Join('http://api.github.com/repos/', $GHRepoName, '/git/trees/', $GHCommit, '?recursive=1')\n    $CodeExtensions = @('.cs', '.vb', '.fs', '.fsi', '.fsx', '.fsscript')\n\n    try {\n      # Retrieve the list of files in the repo at that particular commit point and store them in the RepoFiles hash\n      $Data = Invoke-WebRequest $RepoTreeURL -UseBasicParsing | ConvertFrom-Json | Select-Object -ExpandProperty tree\n  \n      foreach ($file in $Data) {\n        $Extension = [System.IO.Path]::GetExtension($file.path)\n\n        if ($CodeExtensions.Contains($Extension)) {\n          $RepoFiles[$file.path] = 1\n        }\n      }\n    }\n    catch {\n      Write-Host \"Problems downloading the list of files from the repo. Url used: $RepoTreeURL . Execution will proceed without caching.\"\n    }\n  }\n  elseif ($GHRepoName -ne '' -or $GHCommit -ne '') {\n    Write-Host 'For using the http caching mechanism both GHRepoName and GHCommit should be informed.'\n  }\n  \n  if (Test-Path $ExtractPath) {\n    Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue\n  }\n\n  $ValidationFailures = 0\n\n  # Process each NuGet package in parallel\n  Get-ChildItem \"$InputPath\\*.symbols.nupkg\" |\n    ForEach-Object {\n      Write-Host \"Starting $($_.FullName)\"\n      Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName | Out-Null\n      $NumJobs = @(Get-Job -State 'Running').Count\n      \n      while ($NumJobs -ge $MaxParallelJobs) {\n        Write-Host \"There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again.\"\n        sleep $SecondsBetweenLoadChecks\n        $NumJobs = @(Get-Job -State 'Running').Count\n      }\n\n      foreach ($Job in @(Get-Job -State 'Completed')) {\n        $jobResult = Wait-Job -Id $Job.Id | Receive-Job\n        CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures) -LogErrors\n        Remove-Job -Id $Job.Id\n      }\n    }\n\n  foreach ($Job in @(Get-Job)) {\n    $jobResult = Wait-Job -Id $Job.Id | Receive-Job\n    CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures)\n    Remove-Job -Id $Job.Id\n  }\n  if ($ValidationFailures -gt 0) {\n    Write-PipelineTelemetryError -Category 'SourceLink' -Message \"$ValidationFailures package(s) failed validation.\"\n    ExitWithExitCode 1\n  }\n}\n\nfunction InstallSourcelinkCli {\n  $sourcelinkCliPackageName = 'sourcelink'\n\n  $dotnetRoot = InitializeDotNetCli -install:$true\n  $dotnet = \"$dotnetRoot\\dotnet.exe\"\n  $toolList = & \"$dotnet\" tool list --global\n\n  if (($toolList -like \"*$sourcelinkCliPackageName*\") -and ($toolList -like \"*$sourcelinkCliVersion*\")) {\n    Write-Host \"SourceLink CLI version $sourcelinkCliVersion is already installed.\"\n  }\n  else {\n    Write-Host \"Installing SourceLink CLI version $sourcelinkCliVersion...\"\n    Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'\n    & \"$dotnet\" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity \"minimal\" --global \n  }\n}\n\ntry {\n  InstallSourcelinkCli\n\n  foreach ($Job in @(Get-Job)) {\n    Remove-Job -Id $Job.Id\n  }\n\n  ValidateSourceLinkLinks \n}\ncatch {\n  Write-Host $_.Exception\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'SourceLink' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/post-build/symbols-validation.ps1",
    "content": "param(\n  [Parameter(Mandatory = $true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored\n  [Parameter(Mandatory = $true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation\n  [Parameter(Mandatory = $true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use\n  [Parameter(Mandatory = $false)][switch] $CheckForWindowsPdbs, # If we should check for the existence of windows pdbs in addition to portable PDBs\n  [Parameter(Mandatory = $false)][switch] $ContinueOnError, # If we should keep checking symbols after an error\n  [Parameter(Mandatory = $false)][switch] $Clean,           # Clean extracted symbols directory after checking symbols\n  [Parameter(Mandatory = $false)][string] $SymbolExclusionFile  # Exclude the symbols in the file from publishing to symbol server\n)\n\n. $PSScriptRoot\\..\\tools.ps1\n# Maximum number of jobs to run in parallel\n$MaxParallelJobs = 16\n\n# Max number of retries\n$MaxRetry = 5\n\n# Wait time between check for system load\n$SecondsBetweenLoadChecks = 10\n\n# Set error codes\nSet-Variable -Name \"ERROR_BADEXTRACT\" -Option Constant -Value -1\nSet-Variable -Name \"ERROR_FILEDOESNOTEXIST\" -Option Constant -Value -2\n\n$WindowsPdbVerificationParam = \"\"\nif ($CheckForWindowsPdbs) {\n  $WindowsPdbVerificationParam = \"--windows-pdbs\"\n}\n\n$ExclusionSet = New-Object System.Collections.Generic.HashSet[string];\n\nif (!$InputPath -or !(Test-Path $InputPath)){\n  Write-Host \"No symbols to validate.\"\n  ExitWithExitCode 0\n}\n\n#Check if the path exists\nif ($SymbolExclusionFile -and (Test-Path $SymbolExclusionFile)){\n  [string[]]$Exclusions = Get-Content \"$SymbolExclusionFile\"\n  $Exclusions | foreach { if($_ -and $_.Trim()){$ExclusionSet.Add($_)} }\n}\nelse{\n  Write-Host \"Symbol Exclusion file does not exists. No symbols to exclude.\"\n}\n\n$CountMissingSymbols = {\n  param( \n    [string] $PackagePath, # Path to a NuGet package\n    [string] $WindowsPdbVerificationParam # If we should check for the existence of windows pdbs in addition to portable PDBs\n  )\n\n  Add-Type -AssemblyName System.IO.Compression.FileSystem\n\n  Write-Host \"Validating $PackagePath \"\n\n  # Ensure input file exist\n  if (!(Test-Path $PackagePath)) {\n    Write-PipelineTaskError \"Input file does not exist: $PackagePath\"\n    return [pscustomobject]@{\n      result      = $using:ERROR_FILEDOESNOTEXIST\n      packagePath = $PackagePath\n    }\n  }\n  \n  # Extensions for which we'll look for symbols\n  $RelevantExtensions = @('.dll', '.exe', '.so', '.dylib')\n\n  # How many files are missing symbol information\n  $MissingSymbols = 0\n\n  $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)\n  $PackageGuid = New-Guid\n  $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageGuid\n  $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath 'Symbols'\n  \n  try {\n    [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)\n  }\n  catch {\n    Write-Host \"Something went wrong extracting $PackagePath\"\n    Write-Host $_\n    return [pscustomobject]@{\n      result      = $using:ERROR_BADEXTRACT\n      packagePath = $PackagePath\n    }\n  }\n\n  Get-ChildItem -Recurse $ExtractPath |\n  Where-Object { $RelevantExtensions -contains $_.Extension } |\n  ForEach-Object {\n    $FileName = $_.FullName\n    if ($FileName -Match '\\\\ref\\\\') {\n      Write-Host \"`t Ignoring reference assembly file \" $FileName\n      return\n    }\n\n    $FirstMatchingSymbolDescriptionOrDefault = {\n      param( \n        [string] $FullPath, # Full path to the module that has to be checked\n        [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols\n        [string] $WindowsPdbVerificationParam, # Parameter to pass to potential check for windows-pdbs.\n        [string] $SymbolsPath\n      )\n\n      $FileName = [System.IO.Path]::GetFileName($FullPath)\n      $Extension = [System.IO.Path]::GetExtension($FullPath)\n\n      # Those below are potential symbol files that the `dotnet symbol` might\n      # return. Which one will be returned depend on the type of file we are\n      # checking and which type of file was uploaded.\n\n      # The file itself is returned\n      $SymbolPath = $SymbolsPath + '\\' + $FileName\n\n      # PDB file for the module\n      $PdbPath = $SymbolPath.Replace($Extension, '.pdb')\n\n      # PDB file for R2R module (created by crossgen)\n      $NGenPdb = $SymbolPath.Replace($Extension, '.ni.pdb')\n\n      # DBG file for a .so library\n      $SODbg = $SymbolPath.Replace($Extension, '.so.dbg')\n\n      # DWARF file for a .dylib\n      $DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf')\n\n      $dotnetSymbolExe = \"$env:USERPROFILE\\.dotnet\\tools\"\n      $dotnetSymbolExe = Resolve-Path \"$dotnetSymbolExe\\dotnet-symbol.exe\"\n\n      $totalRetries = 0\n\n      while ($totalRetries -lt $using:MaxRetry) {\n\n        # Save the output and get diagnostic output\n        $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String\n\n        if ((Test-Path $PdbPath) -and (Test-path $SymbolPath)) {\n          return 'Module and PDB for Module'\n        }\n        elseif ((Test-Path $NGenPdb) -and (Test-Path $PdbPath) -and (Test-Path $SymbolPath)) {\n          return 'Dll, PDB and NGen PDB'\n        }\n        elseif ((Test-Path $SODbg) -and (Test-Path $SymbolPath)) {\n          return 'So and DBG for SO'\n        }  \n        elseif ((Test-Path $DylibDwarf) -and (Test-Path $SymbolPath)) {\n          return 'Dylib and Dwarf for Dylib'\n        }  \n        elseif (Test-Path $SymbolPath) {\n          return 'Module'\n        }\n        else\n        {\n          $totalRetries++\n        }\n      }\n      \n      return $null\n    }\n\n    $FileRelativePath = $FileName.Replace(\"$ExtractPath\\\", \"\")\n    if (($($using:ExclusionSet) -ne $null) -and ($($using:ExclusionSet).Contains($FileRelativePath) -or ($($using:ExclusionSet).Contains($FileRelativePath.Replace(\"\\\", \"/\"))))){\n      Write-Host \"Skipping $FileName from symbol validation\"\n    }\n\n    else {\n      $FileGuid = New-Guid\n      $ExpandedSymbolsPath = Join-Path -Path $SymbolsPath -ChildPath $FileGuid\n\n      $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault `\n          -FullPath $FileName `\n          -TargetServerParam '--microsoft-symbol-server' `\n          -SymbolsPath \"$ExpandedSymbolsPath-msdl\" `\n          -WindowsPdbVerificationParam $WindowsPdbVerificationParam\n      $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault `\n          -FullPath $FileName `\n          -TargetServerParam '--internal-server' `\n          -SymbolsPath \"$ExpandedSymbolsPath-symweb\" `\n          -WindowsPdbVerificationParam $WindowsPdbVerificationParam\n\n      Write-Host -NoNewLine \"`t Checking file \" $FileName \"... \"\n  \n      if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {\n        Write-Host \"Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)\"\n      }\n      else {\n        $MissingSymbols++\n\n        if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {\n          Write-Host 'No symbols found on MSDL or SymWeb!'\n        }\n        else {\n          if ($SymbolsOnMSDL -eq $null) {\n            Write-Host 'No symbols found on MSDL!'\n          }\n          else {\n            Write-Host 'No symbols found on SymWeb!'\n          }\n        }\n      }\n    }\n  }\n  \n  if ($using:Clean) {\n    Remove-Item $ExtractPath -Recurse -Force\n  }\n  \n  Pop-Location\n\n  return [pscustomobject]@{\n    result      = $MissingSymbols\n    packagePath = $PackagePath\n  }\n}\n\nfunction CheckJobResult(\n  $result, \n  $packagePath,\n  [ref]$DupedSymbols,\n  [ref]$TotalFailures) {\n  if ($result -eq $ERROR_BADEXTRACT) {\n    Write-PipelineTelemetryError -Category 'CheckSymbols' -Message \"$packagePath has duplicated symbol files\"\n    $DupedSymbols.Value++\n  } \n  elseif ($result -eq $ERROR_FILEDOESNOTEXIST) {\n    Write-PipelineTelemetryError -Category 'CheckSymbols' -Message \"$packagePath does not exist\"\n    $TotalFailures.Value++\n  }\n  elseif ($result -gt '0') {\n    Write-PipelineTelemetryError -Category 'CheckSymbols' -Message \"Missing symbols for $result modules in the package $packagePath\"\n    $TotalFailures.Value++\n  }\n  else {\n    Write-Host \"All symbols verified for package $packagePath\"\n  }\n}\n\nfunction CheckSymbolsAvailable {\n  if (Test-Path $ExtractPath) {\n    Remove-Item $ExtractPath -Force  -Recurse -ErrorAction SilentlyContinue\n  }\n\n  $TotalPackages = 0\n  $TotalFailures = 0\n  $DupedSymbols = 0\n\n  Get-ChildItem \"$InputPath\\*.nupkg\" |\n    ForEach-Object {\n      $FileName = $_.Name\n      $FullName = $_.FullName\n\n      # These packages from Arcade-Services include some native libraries that\n      # our current symbol uploader can't handle. Below is a workaround until\n      # we get issue: https://github.com/dotnet/arcade/issues/2457 sorted.\n      if ($FileName -Match 'Microsoft\\.DotNet\\.Darc\\.') {\n        Write-Host \"Ignoring Arcade-services file: $FileName\"\n        Write-Host\n        return\n      }\n      elseif ($FileName -Match 'Microsoft\\.DotNet\\.Maestro\\.Tasks\\.') {\n        Write-Host \"Ignoring Arcade-services file: $FileName\"\n        Write-Host\n        return\n      }\n\n      $TotalPackages++\n\n      Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null\n\n      $NumJobs = @(Get-Job -State 'Running').Count\n\n      while ($NumJobs -ge $MaxParallelJobs) {\n        Write-Host \"There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again.\"\n        sleep $SecondsBetweenLoadChecks\n        $NumJobs = @(Get-Job -State 'Running').Count\n      }\n\n      foreach ($Job in @(Get-Job -State 'Completed')) {\n        $jobResult = Wait-Job -Id $Job.Id | Receive-Job\n        CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)\n        Remove-Job -Id $Job.Id\n      }\n      Write-Host\n    }\n\n  foreach ($Job in @(Get-Job)) {\n    $jobResult = Wait-Job -Id $Job.Id | Receive-Job\n    CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)\n  }\n\n  if ($TotalFailures -gt 0 -or $DupedSymbols -gt 0) {\n    if ($TotalFailures -gt 0) {\n      Write-PipelineTelemetryError -Category 'CheckSymbols' -Message \"Symbols missing for $TotalFailures/$TotalPackages packages\"\n    }\n\n    if ($DupedSymbols -gt 0) {\n      Write-PipelineTelemetryError -Category 'CheckSymbols' -Message \"$DupedSymbols/$TotalPackages packages had duplicated symbol files and could not be extracted\"\n    }\n    \n    ExitWithExitCode 1\n  }\n  else {\n    Write-Host \"All symbols validated!\"\n  }\n}\n\nfunction InstallDotnetSymbol {\n  $dotnetSymbolPackageName = 'dotnet-symbol'\n\n  $dotnetRoot = InitializeDotNetCli -install:$true\n  $dotnet = \"$dotnetRoot\\dotnet.exe\"\n  $toolList = & \"$dotnet\" tool list --global\n\n  if (($toolList -like \"*$dotnetSymbolPackageName*\") -and ($toolList -like \"*$dotnetSymbolVersion*\")) {\n    Write-Host \"dotnet-symbol version $dotnetSymbolVersion is already installed.\"\n  }\n  else {\n    Write-Host \"Installing dotnet-symbol version $dotnetSymbolVersion...\"\n    Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'\n    & \"$dotnet\" tool install $dotnetSymbolPackageName --version $dotnetSymbolVersion --verbosity \"minimal\" --global\n  }\n}\n\ntry {\n  InstallDotnetSymbol\n\n  foreach ($Job in @(Get-Job)) {\n    Remove-Job -Id $Job.Id\n  }\n\n  CheckSymbolsAvailable\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'CheckSymbols' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/retain-build.ps1",
    "content": "\nParam(\n[Parameter(Mandatory=$true)][int] $buildId,\n[Parameter(Mandatory=$true)][string] $azdoOrgUri, \n[Parameter(Mandatory=$true)][string] $azdoProject,\n[Parameter(Mandatory=$true)][string] $token\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n\nfunction Get-AzDOHeaders(\n    [string] $token)\n{\n    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(\":${token}\"))\n    $headers = @{\"Authorization\"=\"Basic $base64AuthInfo\"}\n    return $headers\n}\n\nfunction Update-BuildRetention(\n    [string] $azdoOrgUri,\n    [string] $azdoProject,\n    [int] $buildId,\n    [string] $token)\n{\n    $headers = Get-AzDOHeaders -token $token\n    $requestBody = \"{\n        `\"keepForever`\": `\"true`\"\n    }\"\n\n    $requestUri = \"${azdoOrgUri}/${azdoProject}/_apis/build/builds/${buildId}?api-version=6.0\"\n    write-Host \"Attempting to retain build using the following URI: ${requestUri} ...\"\n\n    try {\n        Invoke-RestMethod -Uri $requestUri -Method Patch -Body $requestBody -Header $headers -contentType \"application/json\"\n        Write-Host \"Updated retention settings for build ${buildId}.\"\n    }\n    catch {\n        Write-Error \"Failed to update retention settings for build: $_.Exception.Response.StatusDescription\"\n        exit 1\n    }\n}\n\nUpdate-BuildRetention -azdoOrgUri $azdoOrgUri -azdoProject $azdoProject -buildId $buildId -token $token\nexit 0\n"
  },
  {
    "path": "eng/common/sdk-task.ps1",
    "content": "[CmdletBinding(PositionalBinding=$false)]\nParam(\n  [string] $configuration = 'Debug',\n  [string] $task,\n  [string] $verbosity = 'minimal',\n  [string] $msbuildEngine = $null,\n  [switch] $restore,\n  [switch] $prepareMachine,\n  [switch][Alias('nobl')]$excludeCIBinaryLog,\n  [switch]$noWarnAsError,\n  [switch] $help,\n  [string] $runtimeSourceFeed = '',\n  [string] $runtimeSourceFeedKey = '',\n  [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties\n)\n\n$ci = $true\n$binaryLog = if ($excludeCIBinaryLog) { $false } else { $true }\n$warnAsError = if ($noWarnAsError) { $false } else { $true }\n\n. $PSScriptRoot\\tools.ps1\n\nfunction Print-Usage() {\n  Write-Host \"Common settings:\"\n  Write-Host \"  -task <value>           Name of Arcade task (name of a project in SdkTasks directory of the Arcade SDK package)\"\n  Write-Host \"  -restore                Restore dependencies\"\n  Write-Host \"  -verbosity <value>      Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]\"\n  Write-Host \"  -help                   Print help and exit\"\n  Write-Host \"\"\n\n  Write-Host \"Advanced settings:\"\n  Write-Host \"  -prepareMachine         Prepare machine for CI run\"\n  Write-Host \"  -msbuildEngine <value>  Msbuild engine to use to run build ('dotnet', 'vs', or unspecified).\"\n  Write-Host \"  -excludeCIBinaryLog     When running on CI, allow no binary log (short: -nobl)\"\n  Write-Host \"\"\n  Write-Host \"Command line arguments not listed above are passed thru to msbuild.\"\n}\n\nfunction Build([string]$target) {\n  $logSuffix = if ($target -eq 'Execute') { '' } else { \".$target\" }\n  $log = Join-Path $LogDir \"$task$logSuffix.binlog\"\n  $binaryLogArg = if ($binaryLog) { \"/bl:$log\" } else { \"\" }\n  $outputPath = Join-Path $ToolsetDir \"$task\\\"\n\n  MSBuild $taskProject `\n    $binaryLogArg `\n    /t:$target `\n    /p:Configuration=$configuration `\n    /p:RepoRoot=$RepoRoot `\n    /p:BaseIntermediateOutputPath=$outputPath `\n    /v:$verbosity `\n    @properties\n}\n\ntry {\n  if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {\n    Print-Usage\n    exit 0\n  }\n\n  if ($task -eq \"\") {\n    Write-PipelineTelemetryError -Category 'Build' -Message \"Missing required parameter '-task <value>'\"\n    Print-Usage\n    ExitWithExitCode 1\n  }\n\n  if( $msbuildEngine -eq \"vs\") {\n    # Ensure desktop MSBuild is available for sdk tasks.\n    if( -not ($GlobalJson.tools.PSObject.Properties.Name -contains \"vs\" )) {\n      $GlobalJson.tools | Add-Member -Name \"vs\" -Value (ConvertFrom-Json \"{ `\"version`\": `\"16.5`\" }\") -MemberType NoteProperty\n    }\n    if( -not ($GlobalJson.tools.PSObject.Properties.Name -match \"xcopy-msbuild\" )) {\n      $GlobalJson.tools | Add-Member -Name \"xcopy-msbuild\" -Value \"18.0.0\" -MemberType NoteProperty\n    }\n    if ($GlobalJson.tools.\"xcopy-msbuild\".Trim() -ine \"none\") {\n        $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools.\"xcopy-msbuild\" -install $true\n    }\n    if ($xcopyMSBuildToolsFolder -eq $null) {\n      throw 'Unable to get xcopy downloadable version of msbuild'\n    }\n\n    $global:_MSBuildExe = \"$($xcopyMSBuildToolsFolder)\\MSBuild\\Current\\Bin\\MSBuild.exe\"\n  }\n\n  $taskProject = GetSdkTaskProject $task\n  if (!(Test-Path $taskProject)) {\n    Write-PipelineTelemetryError -Category 'Build' -Message \"Unknown task: $task\"\n    ExitWithExitCode 1\n  }\n\n  if ($restore) {\n    Build 'Restore'\n  }\n\n  Build 'Execute'\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Category 'Build' -Message $_\n  ExitWithExitCode 1\n}\n\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/sdk-task.sh",
    "content": "#!/usr/bin/env bash\n\nshow_usage() {\n    echo \"Common settings:\"\n    echo \"  --task <value>           Name of Arcade task (name of a project in SdkTasks directory of the Arcade SDK package)\"\n    echo \"  --restore                Restore dependencies\"\n    echo \"  --verbosity <value>      Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]\"\n    echo \"  --help                   Print help and exit\"\n    echo \"\"\n\n    echo \"Advanced settings:\"\n    echo \"  --excludeCIBinarylog     Don't output binary log (short: -nobl)\"\n    echo \"  --noWarnAsError          Do not warn as error\"\n    echo \"\"\n    echo \"Command line arguments not listed above are passed thru to msbuild.\"\n}\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nBuild() {\n    local target=$1\n    local log_suffix=\"\"\n    [[ \"$target\" != \"Execute\" ]] && log_suffix=\".$target\"\n    local log=\"$log_dir/$task$log_suffix.binlog\"\n    local binaryLogArg=\"\"\n    [[ $binary_log == true ]] && binaryLogArg=\"/bl:$log\"\n    local output_path=\"$toolset_dir/$task/\"\n\n    MSBuild \"$taskProject\" \\\n        $binaryLogArg \\\n        /t:\"$target\" \\\n        /p:Configuration=\"$configuration\" \\\n        /p:RepoRoot=\"$repo_root\" \\\n        /p:BaseIntermediateOutputPath=\"$output_path\" \\\n        /v:\"$verbosity\" \\\n        $properties\n}\n\nbinary_log=true\nconfiguration=\"Debug\"\nverbosity=\"minimal\"\nexclude_ci_binary_log=false\nrestore=false\nhelp=false\nproperties=''\nwarnAsError=true\n\nwhile (($# > 0)); do\n  lowerI=\"$(echo $1 | tr \"[:upper:]\" \"[:lower:]\")\"\n  case $lowerI in\n    --task)\n      task=$2\n      shift 2\n      ;;\n    --restore)\n      restore=true\n      shift 1\n      ;;\n    --verbosity)\n      verbosity=$2\n      shift 2\n      ;;\n    --excludecibinarylog|--nobl)\n      binary_log=false\n      exclude_ci_binary_log=true\n      shift 1\n      ;;\n    --noWarnAsError)\n      warnAsError=false\n      shift 1\n      ;;\n    --help)\n      help=true\n      shift 1\n      ;;\n    *)\n      properties=\"$properties $1\"\n      shift 1\n      ;;\n  esac\ndone\n\nci=true\n\nif $help; then\n  show_usage\n  exit 0\nfi\n\n. \"$scriptroot/tools.sh\"\nInitializeToolset\n\nif [[ -z \"$task\" ]]; then\n    Write-PipelineTelemetryError -Category 'Task' -Name 'MissingTask' -Message \"Missing required parameter '-task <value>'\"\n    ExitWithExitCode 1\nfi\n\ntaskProject=$(GetSdkTaskProject \"$task\")\nif [[ ! -e \"$taskProject\" ]]; then\n    Write-PipelineTelemetryError -Category 'Task' -Name 'UnknownTask' -Message \"Unknown task: $task\"\n    ExitWithExitCode 1\nfi\n\nif $restore; then\n    Build \"Restore\"\nfi\n\nBuild \"Execute\"\n\n\nExitWithExitCode 0\n"
  },
  {
    "path": "eng/common/sdl/NuGet.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <solution>\n    <add key=\"disableSourceControlIntegration\" value=\"true\" />\n  </solution>\n  <packageSources>\n    <clear />\n    <add key=\"guardian\" value=\"https://securitytools.pkgs.visualstudio.com/_packaging/Guardian/nuget/v3/index.json\" />\n  </packageSources>\n  <packageSourceMapping>\n    <packageSource key=\"guardian\">\n      <package pattern=\"microsoft.guardian.cli\" />\n    </packageSource>\n  </packageSourceMapping>\n  <disabledPackageSources>\n    <clear />\n  </disabledPackageSources>\n</configuration>\n"
  },
  {
    "path": "eng/common/sdl/configure-sdl-tool.ps1",
    "content": "Param(\n  [string] $GuardianCliLocation,\n  [string] $WorkingDirectory,\n  [string] $TargetDirectory,\n  [string] $GdnFolder,\n  # The list of Guardian tools to configure. For each object in the array:\n  # - If the item is a [hashtable], it must contain these entries:\n  #   - Name = The tool name as Guardian knows it.\n  #   - Scenario = (Optional) Scenario-specific name for this configuration entry. It must be unique\n  #     among all tool entries with the same Name.\n  #   - Args = (Optional) Array of Guardian tool configuration args, like '@(\"Target > C:\\temp\")'\n  # - If the item is a [string] $v, it is treated as '@{ Name=\"$v\" }'\n  [object[]] $ToolsList,\n  [string] $GuardianLoggerLevel='Standard',\n  # Optional: Additional params to add to any tool using CredScan.\n  [string[]] $CrScanAdditionalRunConfigParams,\n  # Optional: Additional params to add to any tool using PoliCheck.\n  [string[]] $PoliCheckAdditionalRunConfigParams,\n  # Optional: Additional params to add to any tool using CodeQL/Semmle.\n  [string[]] $CodeQLAdditionalRunConfigParams,\n  # Optional: Additional params to add to any tool using Binskim.\n  [string[]] $BinskimAdditionalRunConfigParams\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n$disableConfigureToolsetImport = $true\n$global:LASTEXITCODE = 0\n\ntry {\n  # `tools.ps1` checks $ci to perform some actions. Since the SDL\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  # Normalize tools list: all in [hashtable] form with defined values for each key.\n  $ToolsList = $ToolsList |\n    ForEach-Object {\n      if ($_ -is [string]) {\n        $_ = @{ Name = $_ }\n      }\n\n      if (-not ($_['Scenario'])) { $_.Scenario = \"\" }\n      if (-not ($_['Args'])) { $_.Args = @() }\n      $_\n    }\n  \n  Write-Host \"List of tools to configure:\"\n  $ToolsList | ForEach-Object { $_ | Out-String | Write-Host }\n\n  # We store config files in the r directory of .gdn\n  $gdnConfigPath = Join-Path $GdnFolder 'r'\n  $ValidPath = Test-Path $GuardianCliLocation\n\n  if ($ValidPath -eq $False)\n  {\n    Write-PipelineTelemetryError -Force -Category 'Sdl' -Message \"Invalid Guardian CLI Location.\"\n    ExitWithExitCode 1\n  }\n\n  foreach ($tool in $ToolsList) {\n    # Put together the name and scenario to make a unique key.\n    $toolConfigName = $tool.Name\n    if ($tool.Scenario) {\n      $toolConfigName += \"_\" + $tool.Scenario\n    }\n\n    Write-Host \"=== Configuring $toolConfigName...\"\n\n    $gdnConfigFile = Join-Path $gdnConfigPath \"$toolConfigName-configure.gdnconfig\"\n\n    # For some tools, add default and automatic args.\n    switch -Exact ($tool.Name) {\n      'credscan' {\n        if ($targetDirectory) {\n          $tool.Args += \"`\"TargetDirectory < $TargetDirectory`\"\"\n        }\n        $tool.Args += \"`\"OutputType < pre`\"\"\n        $tool.Args += $CrScanAdditionalRunConfigParams\n      }\n      'policheck' {\n        if ($targetDirectory) {\n          $tool.Args += \"`\"Target < $TargetDirectory`\"\"\n        }\n        $tool.Args += $PoliCheckAdditionalRunConfigParams\n      }\n      {$_ -in 'semmle', 'codeql'} {\n        if ($targetDirectory) {\n          $tool.Args += \"`\"SourceCodeDirectory < $TargetDirectory`\"\"\n        }\n        $tool.Args += $CodeQLAdditionalRunConfigParams\n      }\n      'binskim' {\n        if ($targetDirectory) {\n          # Binskim crashes due to specific PDBs. GitHub issue: https://github.com/microsoft/binskim/issues/924.\n          # We are excluding all `_.pdb` files from the scan.\n          $tool.Args += \"`\"Target < $TargetDirectory\\**;-:file|$TargetDirectory\\**\\_.pdb`\"\"\n        }\n        $tool.Args += $BinskimAdditionalRunConfigParams\n      }\n    }\n\n    # Create variable pointing to the args array directly so we can use splat syntax later.\n    $toolArgs = $tool.Args\n\n    # Configure the tool. If args array is provided or the current tool has some default arguments\n    # defined, add \"--args\" and splat each element on the end. Arg format is \"{Arg id} < {Value}\",\n    # one per parameter. Doc page for \"guardian configure\":\n    # https://dev.azure.com/securitytools/SecurityIntegration/_wiki/wikis/Guardian/1395/configure\n    Exec-BlockVerbosely {\n      & $GuardianCliLocation configure `\n        --working-directory $WorkingDirectory `\n        --tool $tool.Name `\n        --output-path $gdnConfigFile `\n        --logger-level $GuardianLoggerLevel `\n        --noninteractive `\n        --force `\n        $(if ($toolArgs) { \"--args\" }) @toolArgs\n      Exit-IfNZEC \"Sdl\"\n    }\n\n    Write-Host \"Created '$toolConfigName' configuration file: $gdnConfigFile\"\n  }\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/sdl/execute-all-sdl-tools.ps1",
    "content": "Param(\n  [string] $GuardianPackageName,                                                                 # Required: the name of guardian CLI package (not needed if GuardianCliLocation is specified)\n  [string] $NugetPackageDirectory,                                                               # Required: directory where NuGet packages are installed (not needed if GuardianCliLocation is specified)\n  [string] $GuardianCliLocation,                                                                 # Optional: Direct location of Guardian CLI executable if GuardianPackageName & NugetPackageDirectory are not specified\n  [string] $Repository=$env:BUILD_REPOSITORY_NAME,                                               # Required: the name of the repository (e.g. dotnet/arcade)\n  [string] $BranchName=$env:BUILD_SOURCEBRANCH,                                                  # Optional: name of branch or version of gdn settings; defaults to master\n  [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY,                                         # Required: the directory where source files are located\n  [string] $ArtifactsDirectory = (Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY ('artifacts')),  # Required: the directory where build artifacts are located\n  [string] $AzureDevOpsAccessToken,                                                              # Required: access token for dnceng; should be provided via KeyVault\n\n  # Optional: list of SDL tools to run on source code. See 'configure-sdl-tool.ps1' for tools list\n  # format.\n  [object[]] $SourceToolsList,\n  # Optional: list of SDL tools to run on built artifacts. See 'configure-sdl-tool.ps1' for tools\n  # list format.\n  [object[]] $ArtifactToolsList,\n  # Optional: list of SDL tools to run without automatically specifying a target directory. See\n  # 'configure-sdl-tool.ps1' for tools list format.\n  [object[]] $CustomToolsList,\n\n  [bool] $TsaPublish=$False,                                                                     # Optional: true will publish results to TSA; only set to true after onboarding to TSA; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaBranchName=$env:BUILD_SOURCEBRANCH,                                               # Optional: required for TSA publish; defaults to $(Build.SourceBranchName); TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaRepositoryName=$env:BUILD_REPOSITORY_NAME,                                        # Optional: TSA repository name; will be generated automatically if not submitted; TSA is the automated framework used to upload test results as bugs.\n  [string] $BuildNumber=$env:BUILD_BUILDNUMBER,                                                  # Optional: required for TSA publish; defaults to $(Build.BuildNumber)\n  [bool] $UpdateBaseline=$False,                                                                 # Optional: if true, will update the baseline in the repository; should only be run after fixing any issues which need to be fixed\n  [bool] $TsaOnboard=$False,                                                                     # Optional: if true, will onboard the repository to TSA; should only be run once; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaInstanceUrl,                                                                      # Optional: only needed if TsaOnboard or TsaPublish is true; the instance-url registered with TSA; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaCodebaseName,                                                                     # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the codebase registered with TSA; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaProjectName,                                                                      # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the project registered with TSA; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaNotificationEmail,                                                                # Optional: only needed if TsaOnboard is true; the email(s) which will receive notifications of TSA bug filings (e.g. alias@microsoft.com); TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaCodebaseAdmin,                                                                    # Optional: only needed if TsaOnboard is true; the aliases which are admins of the TSA codebase (e.g. DOMAIN\\alias); TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaBugAreaPath,                                                                      # Optional: only needed if TsaOnboard is true; the area path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.\n  [string] $TsaIterationPath,                                                                    # Optional: only needed if TsaOnboard is true; the iteration path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.\n  [string] $GuardianLoggerLevel='Standard',                                                      # Optional: the logger level for the Guardian CLI; options are Trace, Verbose, Standard, Warning, and Error\n  [string[]] $CrScanAdditionalRunConfigParams,                                                   # Optional: Additional Params to custom build a CredScan run config in the format @(\"xyz:abc\",\"sdf:1\")\n  [string[]] $PoliCheckAdditionalRunConfigParams,                                                # Optional: Additional Params to custom build a Policheck run config in the format @(\"xyz:abc\",\"sdf:1\")\n  [string[]] $CodeQLAdditionalRunConfigParams,                                                   # Optional: Additional Params to custom build a Semmle/CodeQL run config in the format @(\"xyz < abc\",\"sdf < 1\")\n  [string[]] $BinskimAdditionalRunConfigParams,                                                  # Optional: Additional Params to custom build a Binskim run config in the format @(\"xyz < abc\",\"sdf < 1\")\n  [bool] $BreakOnFailure=$False                                                                  # Optional: Fail the build if there were errors during the run\n)\n\ntry {\n  $ErrorActionPreference = 'Stop'\n  Set-StrictMode -Version 2.0\n  $disableConfigureToolsetImport = $true\n  $global:LASTEXITCODE = 0\n\n  # `tools.ps1` checks $ci to perform some actions. Since the SDL\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  #Replace repo names to the format of org/repo\n  if (!($Repository.contains('/'))) {\n    $RepoName = $Repository -replace '(.*?)-(.*)', '$1/$2';\n  }\n  else{\n    $RepoName = $Repository;\n  }\n\n  if ($GuardianPackageName) {\n    $guardianCliLocation = Join-Path $NugetPackageDirectory (Join-Path $GuardianPackageName (Join-Path 'tools' 'guardian.cmd'))\n  } else {\n    $guardianCliLocation = $GuardianCliLocation\n  }\n\n  $workingDirectory = (Split-Path $SourceDirectory -Parent)\n  $ValidPath = Test-Path $guardianCliLocation\n\n  if ($ValidPath -eq $False)\n  {\n    Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Invalid Guardian CLI Location.'\n    ExitWithExitCode 1\n  }\n\n  Exec-BlockVerbosely {\n    & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel\n  }\n  $gdnFolder = Join-Path $workingDirectory '.gdn'\n\n  if ($TsaOnboard) {\n    if ($TsaCodebaseName -and $TsaNotificationEmail -and $TsaCodebaseAdmin -and $TsaBugAreaPath) {\n      Exec-BlockVerbosely {\n        & $guardianCliLocation tsa-onboard --codebase-name \"$TsaCodebaseName\" --notification-alias \"$TsaNotificationEmail\" --codebase-admin \"$TsaCodebaseAdmin\" --instance-url \"$TsaInstanceUrl\" --project-name \"$TsaProjectName\" --area-path \"$TsaBugAreaPath\" --iteration-path \"$TsaIterationPath\" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel\n      }\n      if ($LASTEXITCODE -ne 0) {\n        Write-PipelineTelemetryError -Force -Category 'Sdl' -Message \"Guardian tsa-onboard failed with exit code $LASTEXITCODE.\"\n        ExitWithExitCode $LASTEXITCODE\n      }\n    } else {\n      Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not onboard to TSA -- not all required values ($TsaCodebaseName, $TsaNotificationEmail, $TsaCodebaseAdmin, $TsaBugAreaPath) were specified.'\n      ExitWithExitCode 1\n    }\n  }\n\n  # Configure a list of tools with a default target directory. Populates the \".gdn/r\" directory.\n  function Configure-ToolsList([object[]] $tools, [string] $targetDirectory) {\n    if ($tools -and $tools.Count -gt 0) {\n      Exec-BlockVerbosely {\n        & $(Join-Path $PSScriptRoot 'configure-sdl-tool.ps1') `\n          -GuardianCliLocation $guardianCliLocation `\n          -WorkingDirectory $workingDirectory `\n          -TargetDirectory $targetDirectory `\n          -GdnFolder $gdnFolder `\n          -ToolsList $tools `\n          -AzureDevOpsAccessToken $AzureDevOpsAccessToken `\n          -GuardianLoggerLevel $GuardianLoggerLevel `\n          -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams `\n          -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams `\n          -CodeQLAdditionalRunConfigParams $CodeQLAdditionalRunConfigParams `\n          -BinskimAdditionalRunConfigParams $BinskimAdditionalRunConfigParams\n        if ($BreakOnFailure) {\n          Exit-IfNZEC \"Sdl\"\n        }\n      }\n    }\n  }\n\n  # Configure Artifact and Source tools with default Target directories.\n  Configure-ToolsList $ArtifactToolsList $ArtifactsDirectory\n  Configure-ToolsList $SourceToolsList $SourceDirectory\n  # Configure custom tools with no default Target directory.\n  Configure-ToolsList $CustomToolsList $null\n\n  # At this point, all tools are configured in the \".gdn\" directory. Run them all in a single call.\n  # (If we used \"run\" multiple times, each run would overwrite data from earlier runs.)\n  Exec-BlockVerbosely {\n    & $(Join-Path $PSScriptRoot 'run-sdl.ps1') `\n      -GuardianCliLocation $guardianCliLocation `\n      -WorkingDirectory $SourceDirectory `\n      -UpdateBaseline $UpdateBaseline `\n      -GdnFolder $gdnFolder\n  }\n\n  if ($TsaPublish) {\n    if ($TsaBranchName -and $BuildNumber) {\n      if (-not $TsaRepositoryName) {\n        $TsaRepositoryName = \"$($Repository)-$($BranchName)\"\n      }\n      Exec-BlockVerbosely {\n        & $guardianCliLocation tsa-publish --all-tools --repository-name \"$TsaRepositoryName\" --branch-name \"$TsaBranchName\" --build-number \"$BuildNumber\" --onboard $True --codebase-name \"$TsaCodebaseName\" --notification-alias \"$TsaNotificationEmail\" --codebase-admin \"$TsaCodebaseAdmin\" --instance-url \"$TsaInstanceUrl\" --project-name \"$TsaProjectName\" --area-path \"$TsaBugAreaPath\" --iteration-path \"$TsaIterationPath\" --working-directory $workingDirectory  --logger-level $GuardianLoggerLevel\n      }\n      if ($LASTEXITCODE -ne 0) {\n        Write-PipelineTelemetryError -Force -Category 'Sdl' -Message \"Guardian tsa-publish failed with exit code $LASTEXITCODE.\"\n        ExitWithExitCode $LASTEXITCODE\n      }\n    } else {\n      Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not publish to TSA -- not all required values ($TsaBranchName, $BuildNumber) were specified.'\n      ExitWithExitCode 1\n    }\n  }\n\n  if ($BreakOnFailure) {\n    Write-Host \"Failing the build in case of breaking results...\"\n    Exec-BlockVerbosely {\n      & $guardianCliLocation break --working-directory $workingDirectory --logger-level $GuardianLoggerLevel\n    }\n  } else {\n    Write-Host \"Letting the build pass even if there were breaking results...\"\n  }\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  exit 1\n}\n"
  },
  {
    "path": "eng/common/sdl/extract-artifact-archives.ps1",
    "content": "# This script looks for each archive file in a directory and extracts it into the target directory.\n# For example, the file \"$InputPath/bin.tar.gz\" extracts to \"$ExtractPath/bin.tar.gz.extracted/**\".\n# Uses the \"tar\" utility added to Windows 10 / Windows 2019 that supports tar.gz and zip.\nparam(\n  # Full path to directory where archives are stored.\n  [Parameter(Mandatory=$true)][string] $InputPath,\n  # Full path to directory to extract archives into. May be the same as $InputPath.\n  [Parameter(Mandatory=$true)][string] $ExtractPath\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n\n$disableConfigureToolsetImport = $true\n\ntry {\n  # `tools.ps1` checks $ci to perform some actions. Since the SDL\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  Measure-Command {\n    $jobs = @()\n\n    # Find archive files for non-Windows and Windows builds.\n    $archiveFiles = @(\n      Get-ChildItem (Join-Path $InputPath \"*.tar.gz\")\n      Get-ChildItem (Join-Path $InputPath \"*.zip\")\n    )\n\n    foreach ($targzFile in $archiveFiles) {\n      $jobs += Start-Job -ScriptBlock {\n        $file = $using:targzFile\n        $fileName = [System.IO.Path]::GetFileName($file)\n        $extractDir = Join-Path $using:ExtractPath \"$fileName.extracted\"\n\n        New-Item $extractDir -ItemType Directory -Force | Out-Null\n\n        Write-Host \"Extracting '$file' to '$extractDir'...\"\n\n        # Pipe errors to stdout to prevent PowerShell detecting them and quitting the job early.\n        # This type of quit skips the catch, so we wouldn't be able to tell which file triggered the\n        # error. Save output so it can be stored in the exception string along with context.\n        $output = tar -xf $file -C $extractDir 2>&1\n        # Handle NZEC manually rather than using Exit-IfNZEC: we are in a background job, so we\n        # don't have access to the outer scope.\n        if ($LASTEXITCODE -ne 0) {\n          throw \"Error extracting '$file': non-zero exit code ($LASTEXITCODE). Output: '$output'\"\n        }\n\n        Write-Host \"Extracted to $extractDir\"\n      }\n    }\n\n    Receive-Job $jobs -Wait\n  }\n}\ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/sdl/extract-artifact-packages.ps1",
    "content": "param(\n  [Parameter(Mandatory=$true)][string] $InputPath,              # Full path to directory where artifact packages are stored\n  [Parameter(Mandatory=$true)][string] $ExtractPath            # Full path to directory where the packages will be extracted\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n\n$disableConfigureToolsetImport = $true\n\nfunction ExtractArtifacts {\n  if (!(Test-Path $InputPath)) {\n    Write-Host \"Input Path does not exist: $InputPath\"\n    ExitWithExitCode 0\n  }\n  $Jobs = @()\n  Get-ChildItem \"$InputPath\\*.nupkg\" |\n    ForEach-Object {\n      $Jobs += Start-Job -ScriptBlock $ExtractPackage -ArgumentList $_.FullName\n    }\n\n  foreach ($Job in $Jobs) {\n    Wait-Job -Id $Job.Id | Receive-Job\n  }\n}\n\ntry {\n  # `tools.ps1` checks $ci to perform some actions. Since the SDL\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  $ExtractPackage = {\n    param( \n      [string] $PackagePath                                 # Full path to a NuGet package\n    )\n\n    if (!(Test-Path $PackagePath)) {\n      Write-PipelineTelemetryError -Category 'Build' -Message \"Input file does not exist: $PackagePath\"\n      ExitWithExitCode 1\n    }\n\n    $RelevantExtensions = @('.dll', '.exe', '.pdb')\n    Write-Host -NoNewLine 'Extracting ' ([System.IO.Path]::GetFileName($PackagePath)) '...'\n\n    $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)\n    $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId\n\n    Add-Type -AssemblyName System.IO.Compression.FileSystem\n\n    [System.IO.Directory]::CreateDirectory($ExtractPath);\n\n    try {\n      $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)\n  \n      $zip.Entries | \n      Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |\n        ForEach-Object {\n            $TargetPath = Join-Path -Path $ExtractPath -ChildPath (Split-Path -Path $_.FullName)\n            [System.IO.Directory]::CreateDirectory($TargetPath);\n\n            $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.FullName\n            [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile)\n          }\n    }\n    catch {\n      Write-Host $_\n      Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n      ExitWithExitCode 1\n    }\n    finally {\n      $zip.Dispose() \n    }\n  }\n  Measure-Command { ExtractArtifacts }\n}\ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/sdl/init-sdl.ps1",
    "content": "Param(\n  [string] $GuardianCliLocation,\n  [string] $Repository,\n  [string] $BranchName='master',\n  [string] $WorkingDirectory,\n  [string] $AzureDevOpsAccessToken,\n  [string] $GuardianLoggerLevel='Standard'\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n$disableConfigureToolsetImport = $true\n$global:LASTEXITCODE = 0\n\n# `tools.ps1` checks $ci to perform some actions. Since the SDL\n# scripts don't necessarily execute in the same agent that run the\n# build.ps1/sh script this variable isn't automatically set.\n$ci = $true\n. $PSScriptRoot\\..\\tools.ps1\n\n# Don't display the console progress UI - it's a huge perf hit\n$ProgressPreference = 'SilentlyContinue'\n\n# Construct basic auth from AzDO access token; construct URI to the repository's gdn folder stored in that repository; construct location of zip file\n$encodedPat = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(\":$AzureDevOpsAccessToken\"))\n$escapedRepository = [Uri]::EscapeDataString(\"/$Repository/$BranchName/.gdn\")\n$uri = \"https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0\"\n$zipFile = \"$WorkingDirectory/gdn.zip\"\n\nAdd-Type -AssemblyName System.IO.Compression.FileSystem\n$gdnFolder = (Join-Path $WorkingDirectory '.gdn')\n\ntry {\n  # if the folder does not exist, we'll do a guardian init and push it to the remote repository\n  Write-Host 'Initializing Guardian...'\n  Write-Host \"$GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel\"\n  & $GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel\n  if ($LASTEXITCODE -ne 0) {\n    Write-PipelineTelemetryError -Force -Category 'Build' -Message \"Guardian init failed with exit code $LASTEXITCODE.\"\n    ExitWithExitCode $LASTEXITCODE\n  }\n  # We create the mainbaseline so it can be edited later\n  Write-Host \"$GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline\"\n  & $GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline\n  if ($LASTEXITCODE -ne 0) {\n    Write-PipelineTelemetryError -Force -Category 'Build' -Message \"Guardian baseline failed with exit code $LASTEXITCODE.\"\n    ExitWithExitCode $LASTEXITCODE\n  }\n  ExitWithExitCode 0\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/sdl/packages.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Microsoft.Guardian.Cli\" version=\"0.199.0\"/>\n</packages>\n"
  },
  {
    "path": "eng/common/sdl/run-sdl.ps1",
    "content": "Param(\n  [string] $GuardianCliLocation,\n  [string] $WorkingDirectory,\n  [string] $GdnFolder,\n  [string] $UpdateBaseline,\n  [string] $GuardianLoggerLevel='Standard'\n)\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n$disableConfigureToolsetImport = $true\n$global:LASTEXITCODE = 0\n\ntry {\n  # `tools.ps1` checks $ci to perform some actions. Since the SDL\n  # scripts don't necessarily execute in the same agent that run the\n  # build.ps1/sh script this variable isn't automatically set.\n  $ci = $true\n  . $PSScriptRoot\\..\\tools.ps1\n\n  # We store config files in the r directory of .gdn\n  $gdnConfigPath = Join-Path $GdnFolder 'r'\n  $ValidPath = Test-Path $GuardianCliLocation\n\n  if ($ValidPath -eq $False)\n  {\n    Write-PipelineTelemetryError -Force -Category 'Sdl' -Message \"Invalid Guardian CLI Location.\"\n    ExitWithExitCode 1\n  }\n\n  $gdnConfigFiles = Get-ChildItem $gdnConfigPath -Recurse -Include '*.gdnconfig'\n  Write-Host \"Discovered Guardian config files:\"\n  $gdnConfigFiles | Out-String | Write-Host\n\n  Exec-BlockVerbosely {\n    & $GuardianCliLocation run `\n      --working-directory $WorkingDirectory `\n      --baseline mainbaseline `\n      --update-baseline $UpdateBaseline `\n      --logger-level $GuardianLoggerLevel `\n      --config @gdnConfigFiles\n    Exit-IfNZEC \"Sdl\"\n  }\n}\ncatch {\n  Write-Host $_.ScriptStackTrace\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/sdl/sdl.ps1",
    "content": "\nfunction Install-Gdn {\n    param(\n        [Parameter(Mandatory=$true)]\n        [string]$Path,\n\n        # If omitted, install the latest version of Guardian, otherwise install that specific version.\n        [string]$Version\n    )\n\n    $ErrorActionPreference = 'Stop'\n    Set-StrictMode -Version 2.0\n    $disableConfigureToolsetImport = $true\n    $global:LASTEXITCODE = 0\n\n    # `tools.ps1` checks $ci to perform some actions. Since the SDL\n    # scripts don't necessarily execute in the same agent that run the\n    # build.ps1/sh script this variable isn't automatically set.\n    $ci = $true\n    . $PSScriptRoot\\..\\tools.ps1\n\n    $argumentList = @(\"install\", \"Microsoft.Guardian.Cli\", \"-Source https://securitytools.pkgs.visualstudio.com/_packaging/Guardian/nuget/v3/index.json\", \"-OutputDirectory $Path\", \"-NonInteractive\", \"-NoCache\")\n\n    if ($Version) {\n        $argumentList += \"-Version $Version\"\n    }\n    \n    Start-Process nuget -Verbose -ArgumentList $argumentList -NoNewWindow -Wait\n\n    $gdnCliPath = Get-ChildItem -Filter guardian.cmd -Recurse -Path $Path\n\n    if (!$gdnCliPath)\n    {\n        Write-PipelineTelemetryError -Category 'Sdl' -Message 'Failure installing Guardian'\n    }\n\n    return $gdnCliPath.FullName\n}"
  },
  {
    "path": "eng/common/sdl/trim-assets-version.ps1",
    "content": "<#\n.SYNOPSIS\nInstall and run the 'Microsoft.DotNet.VersionTools.Cli' tool with the 'trim-artifacts-version' command to trim the version from the NuGet assets file name.\n\n.PARAMETER InputPath\nFull path to directory where artifact packages are stored\n\n.PARAMETER Recursive\nSearch for NuGet packages recursively\n\n#>\n\nParam(\n  [string] $InputPath,\n  [bool] $Recursive = $true\n)\n\n$CliToolName = \"Microsoft.DotNet.VersionTools.Cli\"\n\nfunction Install-VersionTools-Cli {\n  param(\n      [Parameter(Mandatory=$true)][string]$Version\n  )\n\n  Write-Host \"Installing the package '$CliToolName' with a version of '$version' ...\"\n  $feed = \"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json\"\n\n  $argumentList = @(\"tool\", \"install\", \"--local\", \"$CliToolName\", \"--add-source $feed\", \"--no-cache\", \"--version $Version\", \"--create-manifest-if-needed\")\n  Start-Process \"$dotnet\" -Verbose -ArgumentList $argumentList -NoNewWindow -Wait\n}\n\n# -------------------------------------------------------------------\n\nif (!(Test-Path $InputPath)) {\n  Write-Host \"Input Path '$InputPath' does not exist\"\n  ExitWithExitCode 1\n}\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version 2.0\n\n$disableConfigureToolsetImport = $true\n$global:LASTEXITCODE = 0\n\n# `tools.ps1` checks $ci to perform some actions. Since the SDL\n# scripts don't necessarily execute in the same agent that run the\n# build.ps1/sh script this variable isn't automatically set.\n$ci = $true\n. $PSScriptRoot\\..\\tools.ps1\n\ntry {\n  $dotnetRoot = InitializeDotNetCli -install:$true\n  $dotnet = \"$dotnetRoot\\dotnet.exe\"\n\n  $toolsetVersion = Read-ArcadeSdkVersion\n  Install-VersionTools-Cli -Version $toolsetVersion\n\n  $cliToolFound = (& \"$dotnet\" tool list --local | Where-Object {$_.Split(' ')[0] -eq $CliToolName})\n  if ($null -eq $cliToolFound) {\n    Write-PipelineTelemetryError -Force -Category 'Sdl' -Message \"The '$CliToolName' tool is not installed.\"\n    ExitWithExitCode 1\n  }\n\n  Exec-BlockVerbosely {\n    & \"$dotnet\" $CliToolName trim-assets-version `\n      --assets-path $InputPath `\n      --recursive $Recursive\n    Exit-IfNZEC \"Sdl\"\n  }\n}\ncatch {\n  Write-Host $_\n  Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_\n  ExitWithExitCode 1\n}\n"
  },
  {
    "path": "eng/common/template-guidance.md",
    "content": "# Overview\n\nArcade provides templates for public (`/templates`) and 1ES pipeline templates (`/templates-official`) scenarios.  Pipelines which are required to be managed by 1ES pipeline templates should reference `/templates-offical`, all other pipelines may reference `/templates`.\n\n## How to use\n\nBasic guidance is:\n\n- 1ES Pipeline Template or 1ES Microbuild template runs should reference `eng/common/templates-official`. Any internal production-graded pipeline should use these templates.\n\n- All other runs should reference `eng/common/templates`.\n\nSee [azure-pipelines.yml](../../azure-pipelines.yml) (templates-official example) or [azure-pipelines-pr.yml](../../azure-pipelines-pr.yml) (templates example) for examples.\n\n#### The `templateIs1ESManaged` parameter\n\nThe `templateIs1ESManaged` is available on most templates and affects which of the variants is used for nested templates. See [Development Notes](#development-notes) below for more information on the `templateIs1ESManaged1 parameter.\n\n- For templates under `job/`, `jobs/`, `steps`, or `post-build/`, this parameter must be explicitly set.\n\n## Multiple outputs\n\n1ES pipeline templates impose a policy where every publish artifact execution results in additional security scans being injected into your pipeline.  When using `templates-official/jobs/jobs.yml`, Arcade reduces the number of additional security injections by gathering all publishing outputs into the [Build.ArtifactStagingDirectory](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#build-variables-devops-services), and utilizing the [outputParentDirectory](https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-pipeline-templates/features/outputs#multiple-outputs) feature of 1ES pipeline templates.  When implementing your pipeline, if you ensure publish artifacts are located in the `$(Build.ArtifactStagingDirectory)`, and utilize the 1ES provided template context, then you can reduce the number of security scans for your pipeline.\n\nExample:\n``` yaml\n# azure-pipelines.yml\nextends:\n  template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate\n  parameters:\n    stages:\n    - stage: build\n      jobs:\n      - template: /eng/common/templates-official/jobs/jobs.yml@self\n        parameters:\n          # 1ES makes use of outputs to reduce security task injection overhead\n          templateContext:\n            outputs:\n            - output: pipelineArtifact\n              displayName: 'Publish logs from source'\n              continueOnError: true\n              condition: always()\n              targetPath: $(Build.ArtifactStagingDirectory)/artifacts/log\n              artifactName: Logs\n          jobs:\n          - job: Windows\n            steps:\n            - script: echo \"friendly neighborhood\" > artifacts/marvel/spiderman.txt\n          # copy build outputs to artifact staging directory for publishing\n          - task: CopyFiles@2\n              displayName: Gather build output\n              inputs:\n                SourceFolder: '$(System.DefaultWorkingDirectory)/artifacts/marvel'\n                Contents: '**'\n                TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/marvel'\n```\n\nNote: Multiple outputs are ONLY applicable to 1ES PT publishing (only usable when referencing `templates-official`).\n\n## Development notes\n\n**Folder / file structure**\n\n``` text\neng\\common\\\n    [templates || templates-official]\\\n        job\\\n            job.yml                          (shim + artifact publishing logic)\n            onelocbuild.yml                  (shim)\n            publish-build-assets.yml         (shim)\n            source-build.yml                 (shim)\n            source-index-stage1.yml          (shim)\n        jobs\\\n            codeql-build.yml                 (shim)\n            jobs.yml                         (shim)\n            source-build.yml                 (shim)\n        post-build\\\n            post-build.yml                   (shim)\n            common-variabls.yml              (shim)\n            setup-maestro-vars.yml           (shim)\n        steps\\\n            publish-build-artifacts.yml      (logic)\n            publish-pipeline-artifacts.yml   (logic)\n            component-governance.yml         (shim)\n            publish-logs.yml                 (shim)\n            retain-build.yml                 (shim)\n            send-to-helix.yml                (shim)\n            source-build.yml                 (shim)\n        variables\\\n            pool-providers.yml               (logic + redirect) # templates/variables/pool-providers.yml will redirect to templates-official/variables/pool-providers.yml if you are running in the internal project\n            sdl-variables.yml                (logic)\n    core-templates\\\n        job\\\n            job.yml                          (logic)\n            onelocbuild.yml                  (logic)\n            publish-build-assets.yml         (logic)\n            source-build.yml                 (logic)\n            source-index-stage1.yml          (logic)\n        jobs\\\n            codeql-build.yml                 (logic)\n            jobs.yml                         (logic)\n            source-build.yml                 (logic)\n        post-build\\\n            common-variabls.yml              (logic)\n            post-build.yml                   (logic)\n            setup-maestro-vars.yml           (logic)\n        steps\\\n            component-governance.yml         (logic)\n            publish-build-artifacts.yml      (redirect)\n            publish-logs.yml                 (logic)\n            publish-pipeline-artifacts.yml   (redirect)\n            retain-build.yml                 (logic)\n            send-to-helix.yml                (logic)\n            source-build.yml                 (logic)\n        variables\\\n            pool-providers.yml               (redirect)\n```\n\nIn the table above, a file is designated as \"shim\", \"logic\", or \"redirect\".\n\n- shim - represents a yaml file which is an intermediate step between pipeline logic and .Net Core Engineering's templates (`core-templates`) and defines the `is1ESPipeline` parameter value.\n\n- logic - represents actual base template logic.\n\n- redirect- represents a file in `core-templates` which redirects to the \"logic\" file in either `templates` or `templates-official`.\n\nLogic for Arcade's templates live **primarily** in the `core-templates` folder.  The exceptions to the location of the logic files are around artifact publishing, which is handled differently between 1es pipeline templates and standard templates.  `templates` and `templates-official` provide shim entry points which redirect to `core-templates` while also defining the `is1ESPipeline` parameter.  If a shim is referenced in `templates`, then `is1ESPipeline` is set to `false`.  If a shim is referenced in `templates-official`, then `is1ESPipeline` is set to `true`.\n\nWithin `templates` and `templates-official`, the templates at the \"stages\", and \"jobs\" / \"job\" level have been replaced with shims.  Templates at the \"steps\" and \"variables\" level are typically too granular to be replaced with shims and instead persist logic which is directly applicable to either scenario.\n\nWithin `core-templates`, there are a handful of places where logic is dependent on which shim entry point was used.  In those places, we redirect back to the respective logic file in `templates` or `templates-official`.\n"
  },
  {
    "path": "eng/common/templates/job/job.yml",
    "content": "parameters: \n  enablePublishBuildArtifacts: false\n  runAsPublic: false\n# CG related params, unused now and can eventually be removed\n  disableComponentGovernance: unused\n# Sbom related params, unused now and can eventually be removed\n  enableSbom: unused\n  PackageVersion: unused\n  BuildDropPath: unused\n\njobs:\n- template: /eng/common/core-templates/job/job.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ if and(ne(parameter.key, 'steps'), ne(parameter.key, 'is1ESPipeline')) }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n\n    steps:\n    - ${{ each step in parameters.steps }}:\n      - ${{ step }}\n\n    # we don't run CG in public\n    - ${{ if eq(variables['System.TeamProject'], 'public') }}:\n      - script: echo \"##vso[task.setvariable variable=skipComponentGovernanceDetection]true\"\n        displayName: Set skipComponentGovernanceDetection variable\n\n    artifactPublishSteps:\n    - ${{ if ne(parameters.artifacts.publish, '') }}:\n      - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}:\n        - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n          parameters:\n            is1ESPipeline: false\n            args:\n              displayName: Publish pipeline artifacts\n              targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'\n              artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}\n              continueOnError: true\n              condition: succeeded()\n              retryCountOnTaskFailure: 10 # for any files being locked\n        - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n          parameters:\n            is1ESPipeline: false\n            args:\n              displayName: Publish pipeline artifacts\n              targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'\n              artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}_Attempt$(System.JobAttempt)\n              continueOnError: true\n              condition: not(succeeded())\n              retryCountOnTaskFailure: 10 # for any files being locked\n      - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}:\n        - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n          parameters:\n            is1ESPipeline: false\n            args:\n              targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log'\n              artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }}\n              displayName: 'Publish logs'\n              continueOnError: true\n              condition: always()\n              retryCountOnTaskFailure: 10 # for any files being locked\n\n    - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}:\n      - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n        parameters:\n          is1ESPipeline: false\n          args:\n            displayName: Publish Logs\n            targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)'\n            artifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)_Attempt$(System.JobAttempt)' ) }}\n            continueOnError: true\n            condition: always()\n            retryCountOnTaskFailure: 10 # for any files being locked\n\n    - ${{ if eq(parameters.enableBuildRetry, 'true') }}:\n      - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml\n        parameters:\n          is1ESPipeline: false\n          args:\n            targetPath: '$(System.DefaultWorkingDirectory)\\eng\\common\\BuildConfiguration'\n            artifactName: 'BuildConfiguration'\n            displayName: 'Publish build retry configuration'\n            continueOnError: true\n            retryCountOnTaskFailure: 10 # for any files being locked\n"
  },
  {
    "path": "eng/common/templates/job/onelocbuild.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/onelocbuild.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/job/publish-build-assets.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/publish-build-assets.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/job/source-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/source-build.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/job/source-index-stage1.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/source-index-stage1.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/jobs/codeql-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/codeql-build.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/jobs/jobs.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/jobs.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/jobs/source-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/source-build.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/post-build/common-variables.yml",
    "content": "variables:\n- template: /eng/common/core-templates/post-build/common-variables.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/post-build/post-build.yml",
    "content": "stages:\n- template: /eng/common/core-templates/post-build/post-build.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/post-build/setup-maestro-vars.yml",
    "content": "steps:\n- template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/steps/enable-internal-runtimes.yml",
    "content": "# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64'\n# variable with the base64-encoded SAS token, by default\n\nsteps:\n- template: /eng/common/core-templates/steps/enable-internal-runtimes.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/enable-internal-sources.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/enable-internal-sources.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/steps/generate-sbom.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/generate-sbom.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/get-delegation-sas.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/get-delegation-sas.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/get-federated-access-token.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/get-federated-access-token.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates/steps/publish-build-artifacts.yml",
    "content": "parameters:\n- name: is1ESPipeline\n  type: boolean\n  default: false\n\n- name: displayName\n  type: string\n  default: 'Publish to Build Artifact'\n\n- name: condition\n  type: string\n  default: succeeded()\n\n- name: artifactName\n  type: string\n\n- name: pathToPublish\n  type: string\n\n- name: continueOnError\n  type: boolean\n  default: false\n\n- name: publishLocation\n  type: string\n  default: 'Container'\n\n- name: retryCountOnTaskFailure\n  type: string\n  default: 10\n\nsteps:\n- ${{ if eq(parameters.is1ESPipeline, true) }}:\n  - 'eng/common/templates cannot be referenced from a 1ES managed template': error\n- task: PublishBuildArtifacts@1\n  displayName: ${{ parameters.displayName }}\n  condition: ${{ parameters.condition }}\n  ${{ if parameters.continueOnError }}:\n    continueOnError: ${{ parameters.continueOnError }}\n  inputs:\n    PublishLocation: ${{ parameters.publishLocation }}  \n    PathtoPublish: ${{ parameters.pathToPublish }}\n    ${{ if parameters.artifactName }}:\n      ArtifactName: ${{ parameters.artifactName }}\n    ${{ if parameters.retryCountOnTaskFailure }}:\n      retryCountOnTaskFailure: ${{ parameters.retryCountOnTaskFailure }}\n"
  },
  {
    "path": "eng/common/templates/steps/publish-logs.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/publish-logs.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/publish-pipeline-artifacts.yml",
    "content": "parameters:\n- name: is1ESPipeline\n  type: boolean\n  default: false\n\n- name: args\n  type: object\n  default: {}\n\nsteps:\n- ${{ if eq(parameters.is1ESPipeline, true) }}:\n  - 'eng/common/templates cannot be referenced from a 1ES managed template': error\n- task: PublishPipelineArtifact@1\n  displayName: ${{ coalesce(parameters.args.displayName, 'Publish to Build Artifact') }}\n  ${{ if parameters.args.condition }}:\n    condition: ${{ parameters.args.condition }}\n  ${{ else }}:\n    condition: succeeded()\n  ${{ if parameters.args.continueOnError }}:\n    continueOnError: ${{ parameters.args.continueOnError }}\n  inputs:\n    targetPath: ${{ parameters.args.targetPath }}\n    ${{ if parameters.args.artifactName }}:\n      artifactName: ${{ parameters.args.artifactName }}\n    ${{ if parameters.args.publishLocation }}:\n      publishLocation: ${{ parameters.args.publishLocation }}\n    ${{ if parameters.args.fileSharePath }}:\n      fileSharePath: ${{ parameters.args.fileSharePath }}\n    ${{ if parameters.args.Parallel }}:\n      parallel: ${{ parameters.args.Parallel }}\n    ${{ if parameters.args.parallelCount }}:\n      parallelCount: ${{ parameters.args.parallelCount }}\n    ${{ if parameters.args.properties }}:\n      properties: ${{ parameters.args.properties }}"
  },
  {
    "path": "eng/common/templates/steps/retain-build.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/retain-build.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/send-to-helix.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/send-to-helix.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/source-build.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/source-build.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/source-index-stage1-publish.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/source-index-stage1-publish.yml\n  parameters:\n    is1ESPipeline: false\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates/steps/vmr-sync.yml",
    "content": "### These steps synchronize new code from product repositories into the VMR (https://github.com/dotnet/dotnet).\n### They initialize the darc CLI and pull the new updates.\n### Changes are applied locally onto the already cloned VMR (located in $vmrPath).\n\nparameters:\n- name: targetRef\n  displayName: Target revision in dotnet/<repo> to synchronize\n  type: string\n  default: $(Build.SourceVersion)\n\n- name: vmrPath\n  displayName: Path where the dotnet/dotnet is checked out to\n  type: string\n  default: $(Agent.BuildDirectory)/vmr\n\n- name: additionalSyncs\n  displayName: Optional list of package names whose repo's source will also be synchronized in the local VMR, e.g. NuGet.Protocol\n  type: object\n  default: []\n\nsteps:\n- checkout: vmr\n  displayName: Clone dotnet/dotnet\n  path: vmr\n  clean: true\n\n- checkout: self\n  displayName: Clone $(Build.Repository.Name)\n  path: repo\n  fetchDepth: 0\n\n# This step is needed so that when we get a detached HEAD / shallow clone,\n# we still pull the commit into the temporary repo clone to use it during the sync.\n# Also unshallow the clone so that forwardflow command would work.\n- script: |\n    git branch repo-head\n    git rev-parse HEAD\n  displayName: Label PR commit\n  workingDirectory: $(Agent.BuildDirectory)/repo\n\n- script: |\n    git config --global user.name \"dotnet-maestro[bot]\"\n    git config --global user.email \"dotnet-maestro[bot]@users.noreply.github.com\"\n  displayName: Set git author to dotnet-maestro[bot]\n  workingDirectory: ${{ parameters.vmrPath }}\n\n- script: |\n    ./eng/common/vmr-sync.sh                         \\\n      --vmr ${{ parameters.vmrPath }}         \\\n      --tmp $(Agent.TempDirectory)            \\\n      --azdev-pat '$(dn-bot-all-orgs-code-r)' \\\n      --ci                                    \\\n      --debug\n\n    if [ \"$?\" -ne 0 ]; then\n      echo \"##vso[task.logissue type=error]Failed to synchronize the VMR\"\n      exit 1\n    fi\n  displayName: Sync repo into VMR (Unix)\n  condition: ne(variables['Agent.OS'], 'Windows_NT')\n  workingDirectory: $(Agent.BuildDirectory)/repo\n\n- script: |\n    git config --global diff.astextplain.textconv echo\n    git config --system core.longpaths true\n  displayName: Configure Windows git (longpaths, astextplain)\n  condition: eq(variables['Agent.OS'], 'Windows_NT')\n\n- powershell: |\n    ./eng/common/vmr-sync.ps1                      `\n      -vmr ${{ parameters.vmrPath }}        `\n      -tmp $(Agent.TempDirectory)           `\n      -azdevPat '$(dn-bot-all-orgs-code-r)' `\n      -ci                                   `\n      -debugOutput\n\n    if ($LASTEXITCODE -ne 0) {\n      echo \"##vso[task.logissue type=error]Failed to synchronize the VMR\"\n      exit 1\n    }\n  displayName: Sync repo into VMR (Windows)\n  condition: eq(variables['Agent.OS'], 'Windows_NT')\n  workingDirectory: $(Agent.BuildDirectory)/repo\n\n- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:\n  - task: CopyFiles@2\n    displayName: Collect failed patches\n    condition: failed()\n    inputs:\n      SourceFolder: '$(Agent.TempDirectory)'\n      Contents: '*.patch'\n      TargetFolder: '$(Build.ArtifactStagingDirectory)/FailedPatches'\n\n  - publish: '$(Build.ArtifactStagingDirectory)/FailedPatches'\n    artifact: $(System.JobDisplayName)_FailedPatches\n    displayName: Upload failed patches\n    condition: failed()\n\n- ${{ each assetName in parameters.additionalSyncs }}:\n  # The vmr-sync script ends up staging files in the local VMR so we have to commit those\n  - script:\n      git commit --allow-empty -am \"Forward-flow $(Build.Repository.Name)\"\n    displayName: Commit local VMR changes\n    workingDirectory: ${{ parameters.vmrPath }}\n\n  - script: |\n      set -ex\n\n      echo \"Searching for details of asset ${{ assetName }}...\"\n\n      # Use darc to get dependencies information\n      dependencies=$(./.dotnet/dotnet darc get-dependencies --name '${{ assetName }}' --ci)\n\n      # Extract repository URL and commit hash\n      repository=$(echo \"$dependencies\" | grep 'Repo:' | sed 's/Repo:[[:space:]]*//' | head -1)\n\n      if [ -z \"$repository\" ]; then\n        echo \"##vso[task.logissue type=error]Asset ${{ assetName }} not found in the dependency list\"\n        exit 1\n      fi\n\n      commit=$(echo \"$dependencies\" | grep 'Commit:' | sed 's/Commit:[[:space:]]*//' | head -1)\n\n      echo \"Updating the VMR from $repository / $commit...\"\n      cd ..\n      git clone $repository ${{ assetName }}\n      cd ${{ assetName }}\n      git checkout $commit\n      git branch \"sync/$commit\"\n\n      ./eng/common/vmr-sync.sh                         \\\n        --vmr ${{ parameters.vmrPath }}         \\\n        --tmp $(Agent.TempDirectory)            \\\n        --azdev-pat '$(dn-bot-all-orgs-code-r)' \\\n        --ci                                    \\\n        --debug\n\n      if [ \"$?\" -ne 0 ]; then\n        echo \"##vso[task.logissue type=error]Failed to synchronize the VMR\"\n        exit 1\n      fi\n    displayName: Sync ${{ assetName }} into (Unix)\n    condition: ne(variables['Agent.OS'], 'Windows_NT')\n    workingDirectory: $(Agent.BuildDirectory)/repo\n\n  - powershell: |\n      $ErrorActionPreference = 'Stop'\n\n      Write-Host \"Searching for details of asset ${{ assetName }}...\"\n\n      $dependencies = .\\.dotnet\\dotnet darc get-dependencies --name '${{ assetName }}' --ci\n\n      $repository = $dependencies | Select-String -Pattern 'Repo:\\s+([^\\s]+)' | Select-Object -First 1\n      $repository -match 'Repo:\\s+([^\\s]+)' | Out-Null\n      $repository = $matches[1]\n\n      if ($repository -eq $null) {\n          Write-Error \"Asset ${{ assetName }} not found in the dependency list\"\n          exit 1\n      }\n\n      $commit = $dependencies | Select-String -Pattern 'Commit:\\s+([^\\s]+)' | Select-Object -First 1\n      $commit -match 'Commit:\\s+([^\\s]+)' | Out-Null\n      $commit = $matches[1]\n\n      Write-Host \"Updating the VMR from $repository / $commit...\"\n      cd ..\n      git clone $repository ${{ assetName }}\n      cd ${{ assetName }}\n      git checkout $commit\n      git branch \"sync/$commit\"\n\n      .\\eng\\common\\vmr-sync.ps1 `\n        -vmr ${{ parameters.vmrPath }}             `\n        -tmp $(Agent.TempDirectory)                `\n        -azdevPat '$(dn-bot-all-orgs-code-r)'      `\n        -ci                                        `\n        -debugOutput\n\n      if ($LASTEXITCODE -ne 0) {\n        echo \"##vso[task.logissue type=error]Failed to synchronize the VMR\"\n        exit 1\n      }\n    displayName: Sync ${{ assetName }} into (Windows)\n    condition: ne(variables['Agent.OS'], 'Windows_NT')\n    workingDirectory: $(Agent.BuildDirectory)/repo\n"
  },
  {
    "path": "eng/common/templates/variables/pool-providers.yml",
    "content": "# Select a pool provider based off branch name. Anything with branch name containing 'release' must go into an -Svc pool,\n# otherwise it should go into the \"normal\" pools. This separates out the queueing and billing of released branches.\n\n# Motivation:\n#   Once a given branch of a repository's output has been officially \"shipped\" once, it is then considered to be COGS\n#   (Cost of goods sold) and should be moved to a servicing pool provider. This allows both separation of queueing\n#   (allowing release builds and main PR builds to not intefere with each other) and billing (required for COGS.\n#   Additionally, the pool provider name itself may be subject to change when the .NET Core Engineering Services\n#   team needs to move resources around and create new and potentially differently-named pools. Using this template\n#   file from an Arcade-ified repo helps guard against both having to update one's release/* branches and renaming.\n\n# How to use:\n#  This yaml assumes your shipped product branches use the naming convention \"release/...\" (which many do).\n#  If we find alternate naming conventions in broad usage it can be added to the condition below.\n#\n#  First, import the template in an arcade-ified repo to pick up the variables, e.g.:\n#\n#  variables:\n#  - template: /eng/common/templates/variables/pool-providers.yml\n#\n#  ... then anywhere specifying the pool provider use the runtime variables,\n#      $(DncEngInternalBuildPool) and $  (DncEngPublicBuildPool), e.g.:\n#\n#        pool:\n#           name: $(DncEngInternalBuildPool)\n#           demands: ImageOverride -equals windows.vs2026.amd64\nvariables:\n  - ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n    - template: /eng/common/templates-official/variables/pool-providers.yml\n  - ${{ else }}:\n    # Coalesce the target and source branches so we know when a PR targets a release branch\n    # If these variables are somehow missing, fall back to main (tends to have more capacity)\n\n    # Any new -Svc alternative pools should have variables added here to allow for splitting work\n    - name: DncEngPublicBuildPool\n      value: $[\n          replace(\n            replace(\n              eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'),\n              True,\n              'NetCore-Svc-Public'\n            ),\n            False,\n            'NetCore-Public'\n          )\n        ]\n\n    - name: DncEngInternalBuildPool\n      value: $[\n          replace(\n            replace(\n              eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'),\n              True,\n              'NetCore1ESPool-Svc-Internal'\n            ),\n            False,\n            'NetCore1ESPool-Internal'\n          )\n        ]\n"
  },
  {
    "path": "eng/common/templates/vmr-build-pr.yml",
    "content": "# This pipeline is used for running the VMR verification of the PR changes in repo-level PRs.\n#\n# It will run a full set of verification jobs defined in:\n# https://github.com/dotnet/dotnet/blob/10060d128e3f470e77265f8490f5e4f72dae738e/eng/pipelines/templates/stages/vmr-build.yml#L27-L38\n#\n# For repos that do not need to run the full set, you would do the following:\n#\n# 1. Copy this YML file to a repo-specific location, i.e. outside of eng/common.\n#\n# 2. Add `verifications` parameter to VMR template reference\n#\n#    Examples:\n#    - For source-build stage 1 verification, add the following:\n#        verifications: [ \"source-build-stage1\" ]\n#\n#    - For Windows only verifications, add the following:\n#        verifications: [ \"unified-build-windows-x64\", \"unified-build-windows-x86\" ]\n\ntrigger: none\npr: none\n\nvariables:\n- template: /eng/common/templates/variables/pool-providers.yml@self\n\n- name: skipComponentGovernanceDetection  # we run CG on internal builds only\n  value: true\n\n- name: Codeql.Enabled  # we run CodeQL on internal builds only\n  value: false\n\nresources:\n  repositories:\n  - repository: vmr\n    type: github\n    name: dotnet/dotnet\n    endpoint: dotnet\n    ref: refs/heads/main # Set to whatever VMR branch the PR build should insert into\n\nstages:\n- template: /eng/pipelines/templates/stages/vmr-build.yml@vmr\n  parameters:\n    isBuiltFromVmr: false\n    scope: lite\n"
  },
  {
    "path": "eng/common/templates-official/job/job.yml",
    "content": "parameters:\n  runAsPublic: false\n# Sbom related params, unused now and can eventually be removed\n  enableSbom: unused\n  PackageVersion: unused\n  BuildDropPath: unused\n\njobs:\n- template: /eng/common/core-templates/job/job.yml\n  parameters:\n    is1ESPipeline: true\n\n    # publish artifacts\n    # for 1ES managed templates, use the templateContext.output to handle multiple outputs.\n    templateContext:\n      outputParentDirectory: $(Build.ArtifactStagingDirectory)\n      outputs:\n      - ${{ if ne(parameters.artifacts.publish, '') }}:\n        - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}:\n          - output: pipelineArtifact\n            displayName: Publish pipeline artifacts\n            targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'\n            artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}\n            condition: succeeded()\n            retryCountOnTaskFailure: 10 # for any files being locked\n            continueOnError: true\n          - output: pipelineArtifact\n            displayName: Publish pipeline artifacts\n            targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'\n            artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}_Attempt$(System.JobAttempt)\n            condition: not(succeeded())\n            retryCountOnTaskFailure: 10 # for any files being locked\n            continueOnError: true\n        - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}:\n          - output: pipelineArtifact\n            targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log'\n            artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)_Attempt$(System.JobAttempt)') }}\n            displayName: 'Publish logs'\n            continueOnError: true\n            condition: always()\n            retryCountOnTaskFailure: 10 # for any files being locked\n            isProduction: false # logs are non-production artifacts\n\n      - ${{ if eq(parameters.enablePublishBuildArtifacts, true) }}:\n        - output: pipelineArtifact\n          displayName: Publish Logs\n          targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)'\n          artifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)_Attempt$(System.JobAttempt)' ) }}\n          continueOnError: true\n          condition: always()\n          retryCountOnTaskFailure: 10 # for any files being locked\n          isProduction: false # logs are non-production artifacts\n\n      - ${{ if eq(parameters.enableBuildRetry, 'true') }}:\n        - output: pipelineArtifact\n          targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/eng/common/BuildConfiguration'\n          artifactName: 'BuildConfiguration'\n          displayName: 'Publish build retry configuration'\n          continueOnError: true\n          retryCountOnTaskFailure: 10 # for any files being locked\n          isProduction: false # BuildConfiguration is a non-production artifact\n\n      # V4 publishing: automatically publish staged artifacts as a pipeline artifact.\n      # The artifact name matches the SDK's FutureArtifactName ($(System.PhaseName)_Artifacts),\n      # which is encoded in the asset manifest for downstream publishing to discover.\n      # Jobs can opt in by setting enablePublishing: true.\n      - ${{ if and(eq(parameters.publishingVersion, 4), eq(parameters.enablePublishing, 'true')) }}:\n        - output: pipelineArtifact\n          displayName: 'Publish V4 pipeline artifacts'\n          targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'\n          artifactName: '$(System.PhaseName)_Artifacts'\n          continueOnError: true\n          retryCountOnTaskFailure: 10 # for any files being locked\n\n      # add any outputs provided via root yaml\n      - ${{ if ne(parameters.templateContext.outputs, '') }}:\n        - ${{ each output in parameters.templateContext.outputs }}:\n          - ${{ output }}\n      \n      # add any remaining templateContext properties\n      ${{ each context in parameters.templateContext }}:\n        ${{ if and(ne(context.key, 'outputParentDirectory'), ne(context.key, 'outputs')) }}:\n          ${{ context.key }}: ${{ context.value }}\n\n    ${{ each parameter in parameters }}:\n      ${{ if and(ne(parameter.key, 'templateContext'), ne(parameter.key, 'is1ESPipeline')) }}:\n        ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/job/onelocbuild.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/onelocbuild.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/job/publish-build-assets.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/publish-build-assets.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/job/source-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/source-build.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/job/source-index-stage1.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/job/source-index-stage1.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/jobs/codeql-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/codeql-build.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/jobs/jobs.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/jobs.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/jobs/source-build.yml",
    "content": "jobs:\n- template: /eng/common/core-templates/jobs/source-build.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates-official/post-build/common-variables.yml",
    "content": "variables:\n- template: /eng/common/core-templates/post-build/common-variables.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates-official/post-build/post-build.yml",
    "content": "stages:\n- template: /eng/common/core-templates/post-build/post-build.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/post-build/setup-maestro-vars.yml",
    "content": "steps:\n- template: /eng/common/core-templates/post-build/setup-maestro-vars.yml\n  parameters:\n    # Specifies whether to use 1ES\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates-official/steps/enable-internal-runtimes.yml",
    "content": "# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64'\n# variable with the base64-encoded SAS token, by default\nsteps:\n- template: /eng/common/core-templates/steps/enable-internal-runtimes.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/enable-internal-sources.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/enable-internal-sources.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates-official/steps/generate-sbom.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/generate-sbom.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/get-delegation-sas.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/get-delegation-sas.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/get-federated-access-token.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/get-federated-access-token.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}"
  },
  {
    "path": "eng/common/templates-official/steps/publish-build-artifacts.yml",
    "content": "parameters:\n- name: displayName\n  type: string\n  default: 'Publish to Build Artifact'\n\n- name: condition\n  type: string\n  default: succeeded()\n\n- name: artifactName\n  type: string\n\n- name: pathToPublish\n  type: string\n\n- name: continueOnError\n  type: boolean\n  default: false\n\n- name: publishLocation\n  type: string\n  default: 'Container'\n\n- name: is1ESPipeline\n  type: boolean\n  default: true\n\n- name: retryCountOnTaskFailure\n  type: string\n  default: 10\n  \nsteps:\n- ${{ if ne(parameters.is1ESPipeline, true) }}:\n  - 'eng/common/templates-official cannot be referenced from a non-1ES managed template': error\n- task: 1ES.PublishBuildArtifacts@1\n  displayName: ${{ parameters.displayName }}\n  condition: ${{ parameters.condition }}\n  ${{ if parameters.continueOnError }}:\n    continueOnError: ${{ parameters.continueOnError }}\n  inputs:\n    PublishLocation: ${{ parameters.publishLocation }}\n    PathtoPublish: ${{ parameters.pathToPublish }}\n    ${{ if parameters.artifactName }}:\n      ArtifactName: ${{ parameters.artifactName }}\n    ${{ if parameters.retryCountOnTaskFailure }}:\n      retryCountOnTaskFailure: ${{ parameters.retryCountOnTaskFailure }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/publish-logs.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/publish-logs.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/publish-pipeline-artifacts.yml",
    "content": "parameters:\n- name: is1ESPipeline\n  type: boolean\n  default: true\n\n- name: args\n  type: object\n  default: {}\n\nsteps:\n- ${{ if ne(parameters.is1ESPipeline, true) }}:\n  - 'eng/common/templates-official cannot be referenced from a non-1ES managed template': error\n- task: 1ES.PublishPipelineArtifact@1\n  displayName: ${{ coalesce(parameters.args.displayName, 'Publish to Build Artifact') }}\n  ${{ if parameters.args.condition }}:\n    condition: ${{ parameters.args.condition }}\n  ${{ else }}:\n    condition: succeeded()\n  ${{ if parameters.args.continueOnError }}:\n    continueOnError: ${{ parameters.args.continueOnError }}\n  inputs:\n    targetPath: ${{ parameters.args.targetPath }}\n    ${{ if parameters.args.artifactName }}:\n      artifactName: ${{ parameters.args.artifactName }}\n    ${{ if parameters.args.properties }}:\n      properties: ${{ parameters.args.properties }}\n    ${{ if ne(parameters.args.sbomEnabled, '') }}:\n      sbomEnabled: ${{ parameters.args.sbomEnabled }}\n    ${{ if ne(parameters.args.isProduction, '') }}:\n      isProduction: ${{ parameters.args.isProduction }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/retain-build.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/retain-build.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/send-to-helix.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/send-to-helix.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/source-build.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/source-build.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/steps/source-index-stage1-publish.yml",
    "content": "steps:\n- template: /eng/common/core-templates/steps/source-index-stage1-publish.yml\n  parameters:\n    is1ESPipeline: true\n\n    ${{ each parameter in parameters }}:\n      ${{ parameter.key }}: ${{ parameter.value }}\n"
  },
  {
    "path": "eng/common/templates-official/variables/pool-providers.yml",
    "content": "# Select a pool provider based off branch name. Anything with branch name containing 'release' must go into an -Svc pool, \n# otherwise it should go into the \"normal\" pools. This separates out the queueing and billing of released branches.\n\n# Motivation: \n#   Once a given branch of a repository's output has been officially \"shipped\" once, it is then considered to be COGS\n#   (Cost of goods sold) and should be moved to a servicing pool provider. This allows both separation of queueing\n#   (allowing release builds and main PR builds to not intefere with each other) and billing (required for COGS.\n#   Additionally, the pool provider name itself may be subject to change when the .NET Core Engineering Services \n#   team needs to move resources around and create new and potentially differently-named pools. Using this template \n#   file from an Arcade-ified repo helps guard against both having to update one's release/* branches and renaming.\n\n# How to use: \n#  This yaml assumes your shipped product branches use the naming convention \"release/...\" (which many do).\n#  If we find alternate naming conventions in broad usage it can be added to the condition below.\n#\n#  First, import the template in an arcade-ified repo to pick up the variables, e.g.:\n#\n#  variables:\n#  - template: /eng/common/templates-official/variables/pool-providers.yml\n#\n#  ... then anywhere specifying the pool provider use the runtime variables,\n#      $(DncEngInternalBuildPool)\n#\n#        pool:\n#           name: $(DncEngInternalBuildPool)\n#           image: windows.vs2026.amd64\n\nvariables:\n  # Coalesce the target and source branches so we know when a PR targets a release branch\n  # If these variables are somehow missing, fall back to main (tends to have more capacity)\n\n  # Any new -Svc alternative pools should have variables added here to allow for splitting work\n\n  - name: DncEngInternalBuildPool\n    value: $[\n        replace(\n          replace(\n            eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'),\n            True,\n            'NetCore1ESPool-Svc-Internal'\n          ),\n          False,\n          'NetCore1ESPool-Internal'\n        )\n      ]"
  },
  {
    "path": "eng/common/templates-official/variables/sdl-variables.yml",
    "content": "variables:\n# The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in\n# sync with the packages.config file.\n- name: DefaultGuardianVersion\n  value: 0.109.0\n- name: GuardianPackagesConfigFile\n  value: $(System.DefaultWorkingDirectory)\\eng\\common\\sdl\\packages.config"
  },
  {
    "path": "eng/common/tools.ps1",
    "content": "# Initialize variables if they aren't already defined.\n# These may be defined as parameters of the importing script, or set after importing this script.\n\n# CI mode - set to true on CI server for PR validation build or official build.\n[bool]$ci = if (Test-Path variable:ci) { $ci } else { $false }\n\n# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.\n[string]$configuration = if (Test-Path variable:configuration) { $configuration } else { 'Debug' }\n\n# Set to true to opt out of outputting binary log while running in CI\n[bool]$excludeCIBinarylog = if (Test-Path variable:excludeCIBinarylog) { $excludeCIBinarylog } else { $false }\n\n# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.\n[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog }\n\n# Set to true to use the pipelines logger which will enable Azure logging output.\n# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md\n# This flag is meant as a temporary opt-opt for the feature while validate it across\n# our consumers. It will be deleted in the future.\n[bool]$pipelinesLog = if (Test-Path variable:pipelinesLog) { $pipelinesLog } else { $ci }\n\n# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).\n[bool]$prepareMachine = if (Test-Path variable:prepareMachine) { $prepareMachine } else { $false }\n\n# True to restore toolsets and dependencies.\n[bool]$restore = if (Test-Path variable:restore) { $restore } else { $true }\n\n# Adjusts msbuild verbosity level.\n[string]$verbosity = if (Test-Path variable:verbosity) { $verbosity } else { 'minimal' }\n\n# Set to true to reuse msbuild nodes. Recommended to not reuse on CI.\n[bool]$nodeReuse = if (Test-Path variable:nodeReuse) { $nodeReuse } else { !$ci }\n\n# Configures warning treatment in msbuild.\n[bool]$warnAsError = if (Test-Path variable:warnAsError) { $warnAsError } else { $true }\n\n# Specifies which msbuild engine to use for build: 'vs', 'dotnet' or unspecified (determined based on presence of tools.vs in global.json).\n[string]$msbuildEngine = if (Test-Path variable:msbuildEngine) { $msbuildEngine } else { $null }\n\n# True to attempt using .NET Core already that meets requirements specified in global.json\n# installed on the machine instead of downloading one.\n[bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true }\n\n# Enable repos to use a particular version of the on-line dotnet-install scripts.\n#    default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.ps1\n[string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' }\n\n# True to use global NuGet cache instead of restoring packages to repository-local directory.\n[bool]$useGlobalNuGetCache = if (Test-Path variable:useGlobalNuGetCache) { $useGlobalNuGetCache } else { !$ci }\n\n# True to exclude prerelease versions Visual Studio during build\n[bool]$excludePrereleaseVS = if (Test-Path variable:excludePrereleaseVS) { $excludePrereleaseVS } else { $false }\n\n# An array of names of processes to stop on script exit if prepareMachine is true.\n$processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @('msbuild', 'dotnet', 'vbcscompiler') }\n\n$disableConfigureToolsetImport = if (Test-Path variable:disableConfigureToolsetImport) { $disableConfigureToolsetImport } else { $null }\n\nset-strictmode -version 2.0\n$ErrorActionPreference = 'Stop'\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\n# If specifies, provides an alternate path for getting .NET Core SDKs and Runtimes. This script will still try public sources first.\n[string]$runtimeSourceFeed = if (Test-Path variable:runtimeSourceFeed) { $runtimeSourceFeed } else { $null }\n# Base-64 encoded SAS token that has permission to storage container described by $runtimeSourceFeed\n[string]$runtimeSourceFeedKey = if (Test-Path variable:runtimeSourceFeedKey) { $runtimeSourceFeedKey } else { $null }\n\n# True when the build is running within the VMR.\n[bool]$fromVMR = if (Test-Path variable:fromVMR) { $fromVMR } else { $false }\n\nfunction Create-Directory ([string[]] $path) {\n    New-Item -Path $path -Force -ItemType 'Directory' | Out-Null\n}\n\nfunction Unzip([string]$zipfile, [string]$outpath) {\n  Add-Type -AssemblyName System.IO.Compression.FileSystem\n  [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)\n}\n\n# This will exec a process using the console and return it's exit code.\n# This will not throw when the process fails.\n# Returns process exit code.\nfunction Exec-Process([string]$command, [string]$commandArgs) {\n  $startInfo = New-Object System.Diagnostics.ProcessStartInfo\n  $startInfo.FileName = $command\n  $startInfo.Arguments = $commandArgs\n  $startInfo.UseShellExecute = $false\n  $startInfo.WorkingDirectory = Get-Location\n\n  $process = New-Object System.Diagnostics.Process\n  $process.StartInfo = $startInfo\n  $process.Start() | Out-Null\n\n  $finished = $false\n  try {\n    while (-not $process.WaitForExit(100)) {\n      # Non-blocking loop done to allow ctr-c interrupts\n    }\n\n    $finished = $true\n    return $global:LASTEXITCODE = $process.ExitCode\n  }\n  finally {\n    # If we didn't finish then an error occurred or the user hit ctrl-c.  Either\n    # way kill the process\n    if (-not $finished) {\n      $process.Kill()\n    }\n  }\n}\n\n# Take the given block, print it, print what the block probably references from the current set of\n# variables using low-effort string matching, then run the block.\n#\n# This is intended to replace the pattern of manually copy-pasting a command, wrapping it in quotes,\n# and printing it using \"Write-Host\". The copy-paste method is more readable in build logs, but less\n# maintainable and less reliable. It is easy to make a mistake and modify the command without\n# properly updating the \"Write-Host\" line, resulting in misleading build logs. The probability of\n# this mistake makes the pattern hard to trust when it shows up in build logs. Finding the bug in\n# existing source code can also be difficult, because the strings are not aligned to each other and\n# the line may be 300+ columns long.\n#\n# By removing the need to maintain two copies of the command, Exec-BlockVerbosely avoids the issues.\n#\n# In Bash (or any posix-like shell), \"set -x\" prints usable verbose output automatically.\n# \"Set-PSDebug\" appears to be similar at first glance, but unfortunately, it isn't very useful: it\n# doesn't print any info about the variables being used by the command, which is normally the\n# interesting part to diagnose.\nfunction Exec-BlockVerbosely([scriptblock] $block) {\n  Write-Host \"--- Running script block:\"\n  $blockString = $block.ToString().Trim()\n  Write-Host $blockString\n\n  Write-Host \"--- List of variables that might be used:\"\n  # For each variable x in the environment, check the block for a reference to x via simple \"$x\" or\n  # \"@x\" syntax. This doesn't detect other ways to reference variables (\"${x}\" nor \"$variable:x\",\n  # among others). It only catches what this function was originally written for: simple\n  # command-line commands.\n  $variableTable = Get-Variable |\n    Where-Object {\n      $blockString.Contains(\"`$$($_.Name)\") -or $blockString.Contains(\"@$($_.Name)\")\n    } |\n    Format-Table -AutoSize -HideTableHeaders -Wrap |\n    Out-String\n  Write-Host $variableTable.Trim()\n\n  Write-Host \"--- Executing:\"\n  & $block\n  Write-Host \"--- Done running script block!\"\n}\n\n# createSdkLocationFile parameter enables a file being generated under the toolset directory\n# which writes the sdk's location into. This is only necessary for cmd --> powershell invocations\n# as dot sourcing isn't possible.\nfunction InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) {\n  if (Test-Path variable:global:_DotNetInstallDir) {\n    return $global:_DotNetInstallDir\n  }\n\n  # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism\n  $env:DOTNET_MULTILEVEL_LOOKUP=0\n\n  # Disable first run since we do not need all ASP.NET packages restored.\n  $env:DOTNET_NOLOGO=1\n\n  # Disable telemetry on CI.\n  if ($ci) {\n    $env:DOTNET_CLI_TELEMETRY_OPTOUT=1\n  }\n\n  # Find the first path on %PATH% that contains the dotnet.exe\n  if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -eq $null)) {\n    $dotnetExecutable = GetExecutableFileName 'dotnet'\n    $dotnetCmd = Get-Command $dotnetExecutable -ErrorAction SilentlyContinue\n\n    if ($dotnetCmd -ne $null) {\n      $env:DOTNET_INSTALL_DIR = Split-Path $dotnetCmd.Path -Parent\n    }\n  }\n\n  $dotnetSdkVersion = $GlobalJson.tools.dotnet\n\n  # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,\n  # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.\n  if ((-not $globalJsonHasRuntimes) -and (-not [string]::IsNullOrEmpty($env:DOTNET_INSTALL_DIR)) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR \"sdk\\$dotnetSdkVersion\"))) {\n    $dotnetRoot = $env:DOTNET_INSTALL_DIR\n  } else {\n    $dotnetRoot = Join-Path $RepoRoot '.dotnet'\n\n    if (-not (Test-Path(Join-Path $dotnetRoot \"sdk\\$dotnetSdkVersion\"))) {\n      if ($install) {\n        InstallDotNetSdk $dotnetRoot $dotnetSdkVersion\n      } else {\n        Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"Unable to find dotnet with SDK version '$dotnetSdkVersion'\"\n        ExitWithExitCode 1\n      }\n    }\n\n    $env:DOTNET_INSTALL_DIR = $dotnetRoot\n  }\n\n  # Creates a temporary file under the toolset dir.\n  # The following code block is protecting against concurrent access so that this function can\n  # be called in parallel.\n  if ($createSdkLocationFile) {\n    do {\n      $sdkCacheFileTemp = Join-Path $ToolsetDir $([System.IO.Path]::GetRandomFileName())\n    }\n    until (!(Test-Path $sdkCacheFileTemp))\n    Set-Content -Path $sdkCacheFileTemp -Value $dotnetRoot\n\n    try {\n      Move-Item -Force $sdkCacheFileTemp (Join-Path $ToolsetDir 'sdk.txt')\n    } catch {\n      # Somebody beat us\n      Remove-Item -Path $sdkCacheFileTemp\n    }\n  }\n\n  # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom\n  # build steps from using anything other than what we've downloaded.\n  # It also ensures that VS msbuild will use the downloaded sdk targets.\n  $env:PATH = \"$dotnetRoot;$env:PATH\"\n\n  # Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build\n  Write-PipelinePrependPath -Path $dotnetRoot\n\n  Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0'\n  Write-PipelineSetVariable -Name 'DOTNET_NOLOGO' -Value '1'\n\n  return $global:_DotNetInstallDir = $dotnetRoot\n}\n\nfunction Retry($downloadBlock, $maxRetries = 5) {\n  $retries = 1\n\n  while($true) {\n    try {\n      & $downloadBlock\n      break\n    }\n    catch {\n      Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_\n    }\n\n    if (++$retries -le $maxRetries) {\n      $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff\n      Write-Host \"Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries).\"\n      Start-Sleep -Seconds $delayInSeconds\n    }\n    else {\n      Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"Unable to download file in $maxRetries attempts.\"\n      break\n    }\n  }\n}\n\nfunction GetDotNetInstallScript([string] $dotnetRoot) {\n  $installScript = Join-Path $dotnetRoot 'dotnet-install.ps1'\n  $shouldDownload = $false\n  \n  if (!(Test-Path $installScript)) {\n    $shouldDownload = $true\n  } else {\n    # Check if the script is older than 30 days\n    $fileAge = (Get-Date) - (Get-Item $installScript).LastWriteTime\n    if ($fileAge.Days -gt 30) {\n      Write-Host \"Existing install script is too old, re-downloading...\"\n      $shouldDownload = $true\n    }\n  }\n  \n  if ($shouldDownload) {\n    Create-Directory $dotnetRoot\n    $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit\n    $uri = \"https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1\"\n\n    Retry({\n      Write-Host \"GET $uri\"\n      Invoke-WebRequest $uri -UseBasicParsing -OutFile $installScript\n    })\n  }\n\n  return $installScript\n}\n\nfunction InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $architecture = '', [switch] $noPath) {\n  InstallDotNet $dotnetRoot $version $architecture '' $false $runtimeSourceFeed $runtimeSourceFeedKey -noPath:$noPath\n}\n\nfunction InstallDotNet([string] $dotnetRoot,\n  [string] $version,\n  [string] $architecture = '',\n  [string] $runtime = '',\n  [bool] $skipNonVersionedFiles = $false,\n  [string] $runtimeSourceFeed = '',\n  [string] $runtimeSourceFeedKey = '',\n  [switch] $noPath) {\n\n  $dotnetVersionLabel = \"'sdk v$version'\"\n\n  if ($runtime -ne '' -and $runtime -ne 'sdk') {\n    $runtimePath = $dotnetRoot\n    $runtimePath = $runtimePath + \"\\shared\"\n    if ($runtime -eq \"dotnet\") { $runtimePath = $runtimePath + \"\\Microsoft.NETCore.App\" }\n    if ($runtime -eq \"aspnetcore\") { $runtimePath = $runtimePath + \"\\Microsoft.AspNetCore.App\" }\n    if ($runtime -eq \"windowsdesktop\") { $runtimePath = $runtimePath + \"\\Microsoft.WindowsDesktop.App\" }\n    $runtimePath = $runtimePath + \"\\\" + $version\n  \n    $dotnetVersionLabel = \"runtime toolset '$runtime/$architecture v$version'\"\n\n    if (Test-Path $runtimePath) {\n      Write-Host \"  Runtime toolset '$runtime/$architecture v$version' already installed.\"\n      $installSuccess = $true\n      Exit\n    }\n  }\n\n  $installScript = GetDotNetInstallScript $dotnetRoot\n  $installParameters = @{\n    Version = $version\n    InstallDir = $dotnetRoot\n  }\n\n  if ($architecture) { $installParameters.Architecture = $architecture }\n  if ($runtime) { $installParameters.Runtime = $runtime }\n  if ($skipNonVersionedFiles) { $installParameters.SkipNonVersionedFiles = $skipNonVersionedFiles }\n  if ($noPath) { $installParameters.NoPath = $True }\n\n  $variations = @()\n  $variations += @($installParameters)\n\n  $dotnetBuilds = $installParameters.Clone()\n  $dotnetbuilds.AzureFeed = \"https://ci.dot.net/public\"\n  $variations += @($dotnetBuilds)\n\n  if ($runtimeSourceFeed) {\n    $runtimeSource = $installParameters.Clone()\n    $runtimeSource.AzureFeed = $runtimeSourceFeed\n    if ($runtimeSourceFeedKey) {\n      $decodedBytes = [System.Convert]::FromBase64String($runtimeSourceFeedKey)\n      $decodedString = [System.Text.Encoding]::UTF8.GetString($decodedBytes)\n      $runtimeSource.FeedCredential = $decodedString\n    }\n    $variations += @($runtimeSource)\n  }\n\n  $installSuccess = $false\n  foreach ($variation in $variations) {\n    if ($variation | Get-Member AzureFeed) {\n      $location = $variation.AzureFeed\n    } else {\n      $location = \"public location\";\n    }\n    Write-Host \"  Attempting to install $dotnetVersionLabel from $location.\"\n    try {\n      & $installScript @variation\n      $installSuccess = $true\n      break\n    }\n    catch {\n      Write-Host \"  Failed to install $dotnetVersionLabel from $location.\"\n    }\n  }\n  if (-not $installSuccess) {\n    Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"Failed to install $dotnetVersionLabel from any of the specified locations.\"\n    ExitWithExitCode 1\n  }\n}\n\n#\n# Locates Visual Studio MSBuild installation.\n# The preference order for MSBuild to use is as follows:\n#\n#   1. MSBuild from an active VS command prompt\n#   2. MSBuild from a compatible VS installation\n#   3. MSBuild from the xcopy tool package\n#\n# Returns full path to msbuild.exe.\n# Throws on failure.\n#\nfunction InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = $null) {\n  if (-not (IsWindowsPlatform)) {\n    throw \"Cannot initialize Visual Studio on non-Windows\"\n  }\n\n  if (Test-Path variable:global:_MSBuildExe) {\n    return $global:_MSBuildExe\n  }\n\n  # Minimum VS version to require.\n  $vsMinVersionReqdStr = '17.7'\n  $vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr)\n\n  # If the version of msbuild is going to be xcopied,\n  # use this version. Version matches a package here:\n  # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.DotNet.Arcade.MSBuild.Xcopy/versions/18.0.0\n  $defaultXCopyMSBuildVersion = '18.0.0'\n\n  if (!$vsRequirements) {\n    if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {\n      $vsRequirements = $GlobalJson.tools.vs\n    }\n    else {\n      $vsRequirements = New-Object PSObject -Property @{ version = $vsMinVersionReqdStr }\n    }\n  }\n  $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr }\n  $vsMinVersion = [Version]::new($vsMinVersionStr)\n\n  # Try msbuild command available in the environment.\n  if ($env:VSINSTALLDIR -ne $null) {\n    $msbuildCmd = Get-Command 'msbuild.exe' -ErrorAction SilentlyContinue\n    if ($msbuildCmd -ne $null) {\n      # Workaround for https://github.com/dotnet/roslyn/issues/35793\n      # Due to this issue $msbuildCmd.Version returns 0.0.0.0 for msbuild.exe 16.2+\n      $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split([char[]]@('-', '+'))[0])\n\n      if ($msbuildVersion -ge $vsMinVersion) {\n        return $global:_MSBuildExe = $msbuildCmd.Path\n      }\n\n      # Report error - the developer environment is initialized with incompatible VS version.\n      throw \"Developer Command Prompt for VS $($env:VisualStudioVersion) is not recent enough. Please upgrade to $vsMinVersionStr or build from a plain CMD window\"\n    }\n  }\n\n  # Locate Visual Studio installation or download x-copy msbuild.\n  $vsInfo = LocateVisualStudio $vsRequirements\n  if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) {\n    # Ensure vsInstallDir has a trailing slash\n    $vsInstallDir = Join-Path $vsInfo.installationPath \"\\\"\n    $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0]\n\n    InitializeVisualStudioEnvironmentVariables $vsInstallDir $vsMajorVersion\n  } else {\n    if (Get-Member -InputObject $GlobalJson.tools -Name 'xcopy-msbuild') {\n      $xcopyMSBuildVersion = $GlobalJson.tools.'xcopy-msbuild'\n      $vsMajorVersion = $xcopyMSBuildVersion.Split('.')[0]\n    } else {\n      #if vs version provided in global.json is incompatible (too low) then use the default version for xcopy msbuild download\n      if($vsMinVersion -lt $vsMinVersionReqd){\n        Write-Host \"Using xcopy-msbuild version of $defaultXCopyMSBuildVersion since VS version $vsMinVersionStr provided in global.json is not compatible\"\n        $xcopyMSBuildVersion = $defaultXCopyMSBuildVersion\n        $vsMajorVersion = $xcopyMSBuildVersion.Split('.')[0]\n      }\n      else{\n        # If the VS version IS compatible, look for an xcopy msbuild package\n        # with a version matching VS.\n        # Note: If this version does not exist, then an explicit version of xcopy msbuild\n        # can be specified in global.json. This will be required for pre-release versions of msbuild.\n        $vsMajorVersion = $vsMinVersion.Major\n        $vsMinorVersion = $vsMinVersion.Minor\n        $xcopyMSBuildVersion = \"$vsMajorVersion.$vsMinorVersion.0\"\n      }\n    }\n\n    $vsInstallDir = $null\n    if ($xcopyMSBuildVersion.Trim() -ine \"none\") {\n        $vsInstallDir = InitializeXCopyMSBuild $xcopyMSBuildVersion $install\n        if ($vsInstallDir -eq $null) {\n            throw \"Could not xcopy msbuild. Please check that package 'Microsoft.DotNet.Arcade.MSBuild.Xcopy @ $xcopyMSBuildVersion' exists on feed 'dotnet-eng'.\"\n        }\n    }\n    if ($vsInstallDir -eq $null) {\n      throw 'Unable to find Visual Studio that has required version and components installed'\n    }\n  }\n\n  $msbuildVersionDir = if ([int]$vsMajorVersion -lt 16) { \"$vsMajorVersion.0\" } else { \"Current\" }\n\n  $local:BinFolder = Join-Path $vsInstallDir \"MSBuild\\$msbuildVersionDir\\Bin\"\n  $local:Prefer64bit = if (Get-Member -InputObject $vsRequirements -Name 'Prefer64bit') { $vsRequirements.Prefer64bit } else { $false }\n  if ($local:Prefer64bit -and (Test-Path(Join-Path $local:BinFolder \"amd64\"))) {\n    $global:_MSBuildExe = Join-Path $local:BinFolder \"amd64\\msbuild.exe\"\n  } else {\n    $global:_MSBuildExe = Join-Path $local:BinFolder \"msbuild.exe\"\n  }\n\n  return $global:_MSBuildExe\n}\n\nfunction InitializeVisualStudioEnvironmentVariables([string] $vsInstallDir, [string] $vsMajorVersion) {\n  $env:VSINSTALLDIR = $vsInstallDir\n  Set-Item \"env:VS$($vsMajorVersion)0COMNTOOLS\" (Join-Path $vsInstallDir \"Common7\\Tools\\\")\n\n  $vsSdkInstallDir = Join-Path $vsInstallDir \"VSSDK\\\"\n  if (Test-Path $vsSdkInstallDir) {\n    Set-Item \"env:VSSDK$($vsMajorVersion)0Install\" $vsSdkInstallDir\n    $env:VSSDKInstall = $vsSdkInstallDir\n  }\n}\n\nfunction InstallXCopyMSBuild([string]$packageVersion) {\n  return InitializeXCopyMSBuild $packageVersion -install $true\n}\n\nfunction InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) {\n  $packageName = 'Microsoft.DotNet.Arcade.MSBuild.Xcopy'\n  $packageDir = Join-Path $ToolsDir \"msbuild\\$packageVersion\"\n  $packagePath = Join-Path $packageDir \"$packageName.$packageVersion.nupkg\"\n\n  if (!(Test-Path $packageDir)) {\n    if (!$install) {\n      return $null\n    }\n\n    Create-Directory $packageDir\n\n    Write-Host \"Downloading $packageName $packageVersion\"\n    $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit\n    Retry({\n      Invoke-WebRequest \"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg\" -UseBasicParsing -OutFile $packagePath\n    })\n\n    if (!(Test-Path $packagePath)) {\n      Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"See https://dev.azure.com/dnceng/internal/_wiki/wikis/DNCEng%20Services%20Wiki/1074/Updating-Microsoft.DotNet.Arcade.MSBuild.Xcopy-WAS-RoslynTools.MSBuild-(xcopy-msbuild)-generation?anchor=troubleshooting for help troubleshooting issues with XCopy MSBuild\"\n      throw\n    }\n    Unzip $packagePath $packageDir\n  }\n\n  return Join-Path $packageDir 'tools'\n}\n\n#\n# Locates Visual Studio instance that meets the minimal requirements specified by tools.vs object in global.json.\n#\n# The following properties of tools.vs are recognized:\n#   \"version\": \"{major}.{minor}\"\n#       Two part minimal VS version, e.g. \"15.9\", \"16.0\", etc.\n#   \"components\": [\"componentId1\", \"componentId2\", ...]\n#       Array of ids of workload components that must be available in the VS instance.\n#       See e.g. https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-enterprise?view=vs-2017\n#\n# Returns JSON describing the located VS instance (same format as returned by vswhere),\n# or $null if no instance meeting the requirements is found on the machine.\n#\nfunction LocateVisualStudio([object]$vsRequirements = $null){\n  if (-not (IsWindowsPlatform)) {\n    throw \"Cannot run vswhere on non-Windows platforms.\"\n  }\n\n  if (Get-Member -InputObject $GlobalJson.tools -Name 'vswhere') {\n    $vswhereVersion = $GlobalJson.tools.vswhere\n  } else {\n    # keep this in sync with the VSWhereVersion in DefaultVersions.props\n    $vswhereVersion = '3.1.7'\n  }\n\n  $vsWhereDir = Join-Path $ToolsDir \"vswhere\\$vswhereVersion\"\n  $vsWhereExe = Join-Path $vsWhereDir 'vswhere.exe'\n\n  if (!(Test-Path $vsWhereExe)) {\n    Create-Directory $vsWhereDir\n    Write-Host \"Downloading vswhere $vswhereVersion\"\n    $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit\n    Retry({\n      Invoke-WebRequest \"https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe\" -UseBasicParsing -OutFile $vswhereExe\n    })\n  }\n\n  if (!$vsRequirements) {\n    if (Get-Member -InputObject $GlobalJson.tools -Name 'vs' -ErrorAction SilentlyContinue) {\n      $vsRequirements = $GlobalJson.tools.vs\n    } else {\n      $vsRequirements = $null\n    }\n  }\n\n  $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*')\n\n  if (!$excludePrereleaseVS) {\n    $args += '-prerelease'\n  }\n\n  if ($vsRequirements -and (Get-Member -InputObject $vsRequirements -Name 'version' -ErrorAction SilentlyContinue)) {\n    $args += '-version'\n    $args += $vsRequirements.version\n  }\n\n  if ($vsRequirements -and (Get-Member -InputObject $vsRequirements -Name 'components' -ErrorAction SilentlyContinue)) {\n    foreach ($component in $vsRequirements.components) {\n      $args += '-requires'\n      $args += $component\n    }\n  }\n\n  $vsInfo =& $vsWhereExe $args | ConvertFrom-Json\n\n  if ($lastExitCode -ne 0) {\n    return $null\n  }\n\n  # use first matching instance\n  return $vsInfo[0]\n}\n\nfunction InitializeBuildTool() {\n  if (Test-Path variable:global:_BuildTool) {\n    # If the requested msbuild parameters do not match, clear the cached variables.\n    if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) {\n      Remove-Item variable:global:_BuildTool\n      Remove-Item variable:global:_MSBuildExe\n    } else {\n      return $global:_BuildTool\n    }\n  }\n\n  if (-not $msbuildEngine) {\n    $msbuildEngine = GetDefaultMSBuildEngine\n  }\n\n  # Initialize dotnet cli if listed in 'tools'\n  $dotnetRoot = $null\n  if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {\n    $dotnetRoot = InitializeDotNetCli -install:$restore\n  }\n\n  if ($msbuildEngine -eq 'dotnet') {\n    if (!$dotnetRoot) {\n      Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"/global.json must specify 'tools.dotnet'.\"\n      ExitWithExitCode 1\n    }\n    $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet')\n\n    $buildTool = @{ Path = $dotnetPath; Command = 'msbuild'; Tool = 'dotnet'; Framework = 'net' }\n  } elseif ($msbuildEngine -eq \"vs\") {\n    try {\n      $msbuildPath = InitializeVisualStudioMSBuild -install:$restore\n    } catch {\n      Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_\n      ExitWithExitCode 1\n    }\n\n    $buildTool = @{ Path = $msbuildPath; Command = \"\"; Tool = \"vs\"; Framework = \"netframework\"; ExcludePrereleaseVS = $excludePrereleaseVS }\n  } else {\n    Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"Unexpected value of -msbuildEngine: '$msbuildEngine'.\"\n    ExitWithExitCode 1\n  }\n\n  return $global:_BuildTool = $buildTool\n}\n\nfunction GetDefaultMSBuildEngine() {\n  # Presence of tools.vs indicates the repo needs to build using VS msbuild on Windows.\n  if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {\n    return 'vs'\n  }\n\n  if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {\n    return 'dotnet'\n  }\n\n  Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vs'.\"\n  ExitWithExitCode 1\n}\n\nfunction GetNuGetPackageCachePath() {\n  if ($env:NUGET_PACKAGES -eq $null) {\n    # Use local cache on CI to ensure deterministic build.\n    # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116\n    # use global cache in dev builds to avoid cost of downloading packages.\n    # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968\n    if ($useGlobalNuGetCache) {\n      $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\\packages\\'\n    } else {\n      $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\\'\n    }\n  }\n\n  return $env:NUGET_PACKAGES\n}\n\n# Returns a full path to an Arcade SDK task project file.\nfunction GetSdkTaskProject([string]$taskName) {\n  return Join-Path (Split-Path (InitializeToolset) -Parent) \"SdkTasks\\$taskName.proj\"\n}\n\nfunction InitializeNativeTools() {\n  if (-Not (Test-Path variable:DisableNativeToolsetInstalls) -And (Get-Member -InputObject $GlobalJson -Name \"native-tools\")) {\n    $nativeArgs= @{}\n    if ($ci) {\n      $nativeArgs = @{\n        InstallDirectory = \"$ToolsDir\"\n      }\n    }\n    if ($env:NativeToolsOnMachine) {\n      Write-Host \"Variable NativeToolsOnMachine detected, enabling native tool path promotion...\"\n      $nativeArgs += @{ PathPromotion = $true }\n    }\n    & \"$PSScriptRoot/init-tools-native.ps1\" @nativeArgs\n  }\n}\n\nfunction Read-ArcadeSdkVersion() {\n  return $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk'\n}\n\nfunction InitializeToolset() {\n  # For Unified Build/Source-build support, check whether the environment variable is\n  # set. If it is, then use this as the toolset build project.\n  if ($env:_InitializeToolset -ne $null) {\n    return $global:_InitializeToolset = $env:_InitializeToolset\n  }\n\n  if (Test-Path variable:global:_InitializeToolset) {\n    return $global:_InitializeToolset\n  }\n\n  $nugetCache = GetNuGetPackageCachePath\n\n  $toolsetVersion = Read-ArcadeSdkVersion\n  $toolsetLocationFile = Join-Path $ToolsetDir \"$toolsetVersion.txt\"\n\n  if (Test-Path $toolsetLocationFile) {\n    $path = Get-Content $toolsetLocationFile -TotalCount 1\n    if (Test-Path $path) {\n      return $global:_InitializeToolset = $path\n    }\n  }\n\n  if (-not $restore) {\n    Write-PipelineTelemetryError -Category 'InitializeToolset' -Message \"Toolset version $toolsetVersion has not been restored.\"\n    ExitWithExitCode 1\n  }\n\n  $buildTool = InitializeBuildTool\n\n  $proj = Join-Path $ToolsetDir 'restore.proj'\n  $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'ToolsetRestore.binlog') } else { '' }\n\n  '<Project Sdk=\"Microsoft.DotNet.Arcade.Sdk\"/>' | Set-Content $proj\n\n  MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile\n\n  $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1\n  if (!(Test-Path $path)) {\n    throw \"Invalid toolset path: $path\"\n  }\n\n  return $global:_InitializeToolset = $path\n}\n\nfunction ExitWithExitCode([int] $exitCode) {\n  if ($ci -and $prepareMachine) {\n    Stop-Processes\n  }\n  exit $exitCode\n}\n\n# Check if $LASTEXITCODE is a nonzero exit code (NZEC). If so, print a Azure Pipeline error for\n# diagnostics, then exit the script with the $LASTEXITCODE.\nfunction Exit-IfNZEC([string] $category = \"General\") {\n  Write-Host \"Exit code $LASTEXITCODE\"\n  if ($LASTEXITCODE -ne 0) {\n    $message = \"Last command failed with exit code $LASTEXITCODE.\"\n    Write-PipelineTelemetryError -Force -Category $category -Message $message\n    ExitWithExitCode $LASTEXITCODE\n  }\n}\n\nfunction Stop-Processes() {\n  Write-Host 'Killing running build processes...'\n  foreach ($processName in $processesToStopOnExit) {\n    Get-Process -Name $processName -ErrorAction SilentlyContinue | Stop-Process\n  }\n}\n\n#\n# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function.\n# The arguments are automatically quoted.\n# Terminates the script if the build fails.\n#\nfunction MSBuild() {\n  if ($pipelinesLog) {\n    $buildTool = InitializeBuildTool\n\n    if ($ci -and $buildTool.Tool -eq 'dotnet') {\n      $env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20\n      $env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20\n      Write-PipelineSetVariable -Name 'NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS' -Value '20'\n      Write-PipelineSetVariable -Name 'NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS' -Value '20'\n    }\n\n    Enable-Nuget-EnhancedRetry\n\n    $toolsetBuildProject = InitializeToolset\n    $basePath = Split-Path -parent $toolsetBuildProject\n    $selectedPath = Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll')\n\n    if (-not $selectedPath) {\n      Write-PipelineTelemetryError -Category 'Build' -Message \"Unable to find arcade sdk logger assembly: $selectedPath\"\n      ExitWithExitCode 1\n    }\n\n    $args += \"/logger:$selectedPath\"\n  }\n\n  MSBuild-Core @args\n}\n\n#\n# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function.\n# The arguments are automatically quoted.\n# Terminates the script if the build fails.\n#\nfunction MSBuild-Core() {\n  if ($ci) {\n    if (!$binaryLog -and !$excludeCIBinarylog) {\n      Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.'\n      ExitWithExitCode 1\n    }\n\n    if ($nodeReuse) {\n      Write-PipelineTelemetryError -Category 'Build' -Message 'Node reuse must be disabled in CI build.'\n      ExitWithExitCode 1\n    }\n  }\n\n  Enable-Nuget-EnhancedRetry\n\n  $buildTool = InitializeBuildTool\n\n  $cmdArgs = \"$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci\"\n\n  # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable\n  if ($env:MSBUILD_MT_ENABLED -eq \"1\") {\n    $cmdArgs += ' -mt'\n  }\n\n  if ($warnAsError) {\n    $cmdArgs += ' /warnaserror /p:TreatWarningsAsErrors=true'\n  }\n  else {\n    $cmdArgs += ' /p:TreatWarningsAsErrors=false'\n  }\n\n  foreach ($arg in $args) {\n    if ($null -ne $arg -and $arg.Trim() -ne \"\") {\n      if ($arg.EndsWith('\\')) {\n        $arg = $arg + \"\\\"\n      }\n      $cmdArgs += \" `\"$arg`\"\"\n    }\n  }\n\n  # Be sure quote the path in case there are spaces in the dotnet installation location.\n  $env:ARCADE_BUILD_TOOL_COMMAND = \"`\"$($buildTool.Path)`\" $cmdArgs\"\n\n  $exitCode = Exec-Process $buildTool.Path $cmdArgs\n\n  if ($exitCode -ne 0) {\n    # We should not Write-PipelineTaskError here because that message shows up in the build summary\n    # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.\n    Write-Host \"Build failed with exit code $exitCode. Check errors above.\" -ForegroundColor Red\n\n    $buildLog = GetMSBuildBinaryLogCommandLineArgument $args\n    if ($null -ne $buildLog) {\n      Write-Host \"See log: $buildLog\" -ForegroundColor DarkGray\n    }\n\n    # When running on Azure Pipelines, override the returned exit code to avoid double logging.\n    # Skip this when the build is a child of the VMR build.\n    if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) {\n      Write-PipelineSetResult -Result \"Failed\" -Message \"msbuild execution failed.\"\n      # Exiting with an exit code causes the azure pipelines task to log yet another \"noise\" error\n      # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error\n      ExitWithExitCode 0\n    } else {\n      ExitWithExitCode $exitCode\n    }\n  }\n}\n\nfunction GetMSBuildBinaryLogCommandLineArgument($arguments) {\n  foreach ($argument in $arguments) {\n    if ($argument -ne $null) {\n      $arg = $argument.Trim()\n      if ($arg.StartsWith('/bl:', \"OrdinalIgnoreCase\")) {\n        return $arg.Substring('/bl:'.Length)\n      }\n\n      if ($arg.StartsWith('/binaryLogger:', 'OrdinalIgnoreCase')) {\n        return $arg.Substring('/binaryLogger:'.Length)\n      }\n    }\n  }\n\n  return $null\n}\n\nfunction GetExecutableFileName($baseName) {\n  if (IsWindowsPlatform) {\n    return \"$baseName.exe\"\n  }\n  else {\n    return $baseName\n  }\n}\n\nfunction IsWindowsPlatform() {\n  return [environment]::OSVersion.Platform -eq [PlatformID]::Win32NT\n}\n\nfunction Get-Darc($version) {\n  $darcPath  = \"$TempDir\\darc\\$([guid]::NewGuid())\"\n  if ($version -ne $null) {\n    & $PSScriptRoot\\darc-init.ps1 -toolpath $darcPath -darcVersion $version | Out-Host\n  } else {\n    & $PSScriptRoot\\darc-init.ps1 -toolpath $darcPath | Out-Host\n  }\n  return \"$darcPath\\darc.exe\"\n}\n\n. $PSScriptRoot\\pipeline-logging-functions.ps1\n\n$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\\..\\')\n$EngRoot = Resolve-Path (Join-Path $PSScriptRoot '..')\n$ArtifactsDir = Join-Path $RepoRoot 'artifacts'\n$ToolsetDir = Join-Path $ArtifactsDir 'toolset'\n$ToolsDir = Join-Path $RepoRoot '.tools'\n$LogDir = Join-Path (Join-Path $ArtifactsDir 'log') $configuration\n$TempDir = Join-Path (Join-Path $ArtifactsDir 'tmp') $configuration\n$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot 'global.json') | ConvertFrom-Json\n# true if global.json contains a \"runtimes\" section\n$globalJsonHasRuntimes = if ($GlobalJson.tools.PSObject.Properties.Name -Match 'runtimes') { $true } else { $false }\n\nCreate-Directory $ToolsetDir\nCreate-Directory $TempDir\nCreate-Directory $LogDir\n\nWrite-PipelineSetVariable -Name 'Artifacts' -Value $ArtifactsDir\nWrite-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir\nWrite-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir\nWrite-PipelineSetVariable -Name 'TEMP' -Value $TempDir\nWrite-PipelineSetVariable -Name 'TMP' -Value $TempDir\n\n# Import custom tools configuration, if present in the repo.\n# Note: Import in global scope so that the script set top-level variables without qualification.\nif (!$disableConfigureToolsetImport) {\n  $configureToolsetScript = Join-Path $EngRoot 'configure-toolset.ps1'\n  if (Test-Path $configureToolsetScript) {\n    . $configureToolsetScript\n    if ((Test-Path variable:failOnConfigureToolsetError) -And $failOnConfigureToolsetError) {\n      if ((Test-Path variable:LastExitCode) -And ($LastExitCode -ne 0)) {\n        Write-PipelineTelemetryError -Category 'Build' -Message 'configure-toolset.ps1 returned a non-zero exit code'\n        ExitWithExitCode $LastExitCode\n      }\n    }\n  }\n}\n\n#\n# If $ci flag is set, turn on (and log that we did) special environment variables for improved Nuget client retry logic.\n#\nfunction Enable-Nuget-EnhancedRetry() {\n    if ($ci) {\n      Write-Host \"Setting NUGET enhanced retry environment variables\"\n      $env:NUGET_ENABLE_ENHANCED_HTTP_RETRY = 'true'\n      $env:NUGET_ENHANCED_MAX_NETWORK_TRY_COUNT = 6\n      $env:NUGET_ENHANCED_NETWORK_RETRY_DELAY_MILLISECONDS = 1000\n      $env:NUGET_RETRY_HTTP_429 = 'true'\n      Write-PipelineSetVariable -Name 'NUGET_ENABLE_ENHANCED_HTTP_RETRY' -Value 'true'\n      Write-PipelineSetVariable -Name 'NUGET_ENHANCED_MAX_NETWORK_TRY_COUNT' -Value '6'\n      Write-PipelineSetVariable -Name 'NUGET_ENHANCED_NETWORK_RETRY_DELAY_MILLISECONDS' -Value '1000'\n      Write-PipelineSetVariable -Name 'NUGET_RETRY_HTTP_429' -Value 'true'\n    }\n}\n"
  },
  {
    "path": "eng/common/tools.sh",
    "content": "#!/usr/bin/env bash\n\n# Initialize variables if they aren't already defined.\n\n# CI mode - set to true on CI server for PR validation build or official build.\nci=${ci:-false}\n\n# Build mode\nsource_build=${source_build:-false}\n\n# Set to true to use the pipelines logger which will enable Azure logging output.\n# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md\n# This flag is meant as a temporary opt-opt for the feature while validate it across\n# our consumers. It will be deleted in the future.\nif [[ \"$ci\" == true ]]; then\n  pipelines_log=${pipelines_log:-true}\nelse\n  pipelines_log=${pipelines_log:-false}\nfi\n\n# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.\nconfiguration=${configuration:-'Debug'}\n\n# Set to true to opt out of outputting binary log while running in CI\nexclude_ci_binary_log=${exclude_ci_binary_log:-false}\n\nif [[ \"$ci\" == true && \"$exclude_ci_binary_log\" == false ]]; then\n  binary_log_default=true\nelse\n  binary_log_default=false\nfi\n\n# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.\nbinary_log=${binary_log:-$binary_log_default}\n\n# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).\nprepare_machine=${prepare_machine:-false}\n\n# True to restore toolsets and dependencies.\nrestore=${restore:-true}\n\n# Adjusts msbuild verbosity level.\nverbosity=${verbosity:-'minimal'}\n\n# Set to true to reuse msbuild nodes. Recommended to not reuse on CI.\nif [[ \"$ci\" == true ]]; then\n  node_reuse=${node_reuse:-false}\nelse\n  node_reuse=${node_reuse:-true}\nfi\n\n# Configures warning treatment in msbuild.\nwarn_as_error=${warn_as_error:-true}\n\n# True to attempt using .NET Core already that meets requirements specified in global.json\n# installed on the machine instead of downloading one.\nuse_installed_dotnet_cli=${use_installed_dotnet_cli:-true}\n\n# Enable repos to use a particular version of the on-line dotnet-install scripts.\n#    default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.sh\ndotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'}\n\n# True to use global NuGet cache instead of restoring packages to repository-local directory.\n# Keep in sync with NuGetPackageroot in Arcade SDK's RepositoryLayout.props.\nif [[ \"$ci\" == true || \"$source_build\" == true ]]; then\n  use_global_nuget_cache=${use_global_nuget_cache:-false}\nelse\n  use_global_nuget_cache=${use_global_nuget_cache:-true}\nfi\n\n# Used when restoring .NET SDK from alternative feeds\nruntime_source_feed=${runtime_source_feed:-''}\nruntime_source_feed_key=${runtime_source_feed_key:-''}\n\n# True when the build is running within the VMR.\nfrom_vmr=${from_vmr:-false}\n\n# Resolve any symlinks in the given path.\nfunction ResolvePath {\n  local path=$1\n\n  while [[ -h $path ]]; do\n    local dir=\"$( cd -P \"$( dirname \"$path\" )\" && pwd )\"\n    path=\"$(readlink \"$path\")\"\n\n    # if $path was a relative symlink, we need to resolve it relative to the path where the\n    # symlink file was located\n    [[ $path != /* ]] && path=\"$dir/$path\"\n  done\n\n  # return value\n  _ResolvePath=\"$path\"\n}\n\n# ReadVersionFromJson [json key]\nfunction ReadGlobalVersion {\n  local key=$1\n\n  if command -v jq &> /dev/null; then\n    _ReadGlobalVersion=\"$(jq -r \".[] | select(has(\\\"$key\\\")) | .\\\"$key\\\"\" \"$global_json_file\")\"\n  elif [[ \"$(cat \"$global_json_file\")\" =~ \\\"$key\\\"[[:space:]\\:]*\\\"([^\\\"]+) ]]; then\n    _ReadGlobalVersion=${BASH_REMATCH[1]}\n  fi\n\n  if [[ -z \"$_ReadGlobalVersion\" ]]; then\n    Write-PipelineTelemetryError -category 'Build' \"Error: Cannot find \\\"$key\\\" in $global_json_file\"\n    ExitWithExitCode 1\n  fi\n}\n\nfunction InitializeDotNetCli {\n  if [[ -n \"${_InitializeDotNetCli:-}\" ]]; then\n    return\n  fi\n\n  local install=$1\n\n  # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism\n  export DOTNET_MULTILEVEL_LOOKUP=0\n\n  # Disable first run since we want to control all package sources\n  export DOTNET_NOLOGO=1\n\n  # Disable telemetry on CI\n  if [[ $ci == true ]]; then\n    export DOTNET_CLI_TELEMETRY_OPTOUT=1\n  fi\n\n  # LTTNG is the logging infrastructure used by Core CLR. Need this variable set\n  # so it doesn't output warnings to the console.\n  export LTTNG_HOME=\"$HOME\"\n\n  # Find the first path on $PATH that contains the dotnet.exe\n  if [[ \"$use_installed_dotnet_cli\" == true && $global_json_has_runtimes == false && -z \"${DOTNET_INSTALL_DIR:-}\" ]]; then\n    local dotnet_path=`command -v dotnet`\n    if [[ -n \"$dotnet_path\" ]]; then\n      ResolvePath \"$dotnet_path\"\n      export DOTNET_INSTALL_DIR=`dirname \"$_ResolvePath\"`\n    fi\n  fi\n\n  ReadGlobalVersion \"dotnet\"\n  local dotnet_sdk_version=$_ReadGlobalVersion\n  local dotnet_root=\"\"\n\n  # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,\n  # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.\n  if [[ $global_json_has_runtimes == false && -n \"${DOTNET_INSTALL_DIR:-}\" && -d \"$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version\" ]]; then\n    dotnet_root=\"$DOTNET_INSTALL_DIR\"\n  else\n    dotnet_root=\"${repo_root}.dotnet\"\n\n    export DOTNET_INSTALL_DIR=\"$dotnet_root\"\n\n    if [[ ! -d \"$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version\" ]]; then\n      if [[ \"$install\" == true ]]; then\n        InstallDotNetSdk \"$dotnet_root\" \"$dotnet_sdk_version\"\n      else\n        Write-PipelineTelemetryError -category 'InitializeToolset' \"Unable to find dotnet with SDK version '$dotnet_sdk_version'\"\n        ExitWithExitCode 1\n      fi\n    fi\n  fi\n\n  # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom\n  # build steps from using anything other than what we've downloaded.\n  Write-PipelinePrependPath -path \"$dotnet_root\"\n\n  Write-PipelineSetVariable -name \"DOTNET_MULTILEVEL_LOOKUP\" -value \"0\"\n  Write-PipelineSetVariable -name \"DOTNET_NOLOGO\" -value \"1\"\n\n  # return value\n  _InitializeDotNetCli=\"$dotnet_root\"\n}\n\nfunction InstallDotNetSdk {\n  local root=$1\n  local version=$2\n  local architecture=\"unset\"\n  if [[ $# -ge 3 ]]; then\n    architecture=$3\n  fi\n  InstallDotNet \"$root\" \"$version\" $architecture 'sdk' 'true' $runtime_source_feed $runtime_source_feed_key\n}\n\nfunction InstallDotNet {\n  local root=$1\n  local version=$2\n  local runtime=$4\n\n  local dotnetVersionLabel=\"'$runtime v$version'\"\n  if [[ -n \"${4:-}\" ]] && [ \"$4\" != 'sdk' ]; then\n    runtimePath=\"$root\"\n    runtimePath=\"$runtimePath/shared\"\n    case \"$runtime\" in\n      dotnet)\n        runtimePath=\"$runtimePath/Microsoft.NETCore.App\"\n        ;;\n      aspnetcore)\n        runtimePath=\"$runtimePath/Microsoft.AspNetCore.App\"\n        ;;\n      windowsdesktop)\n        runtimePath=\"$runtimePath/Microsoft.WindowsDesktop.App\"\n        ;;\n      *)\n        ;;\n    esac\n    runtimePath=\"$runtimePath/$version\"\n\n    dotnetVersionLabel=\"runtime toolset '$runtime/$architecture v$version'\"\n\n    if [ -d \"$runtimePath\" ]; then\n      echo \"  Runtime toolset '$runtime/$architecture v$version' already installed.\"\n      local installSuccess=1\n      return\n    fi\n  fi\n\n  GetDotNetInstallScript \"$root\"\n  local install_script=$_GetDotNetInstallScript\n\n  local installParameters=(--version $version --install-dir \"$root\")\n\n  if [[ -n \"${3:-}\" ]] && [ \"$3\" != 'unset' ]; then\n    installParameters+=(--architecture $3)\n  fi\n  if [[ -n \"${4:-}\" ]] && [ \"$4\" != 'sdk' ]; then\n    installParameters+=(--runtime $4)\n  fi\n  if [[ \"$#\" -ge \"5\" ]] && [[ \"$5\" != 'false' ]]; then\n    installParameters+=(--skip-non-versioned-files)\n  fi\n\n  local variations=() # list of variable names with parameter arrays in them\n\n  local public_location=(\"${installParameters[@]}\")\n  variations+=(public_location)\n\n  local dotnetbuilds=(\"${installParameters[@]}\" --azure-feed \"https://ci.dot.net/public\")\n  variations+=(dotnetbuilds)\n\n  if [[ -n \"${6:-}\" ]]; then\n    variations+=(private_feed)\n    local private_feed=(\"${installParameters[@]}\" --azure-feed $6)\n    if [[ -n \"${7:-}\" ]]; then\n      # The 'base64' binary on alpine uses '-d' and doesn't support '--decode'\n      # '-d'. To work around this, do a simple detection and switch the parameter\n      # accordingly.\n      decodeArg=\"--decode\"\n      if base64 --help 2>&1 | grep -q \"BusyBox\"; then\n          decodeArg=\"-d\"\n      fi\n      decodedFeedKey=`echo $7 | base64 $decodeArg`\n      private_feed+=(--feed-credential $decodedFeedKey)\n    fi\n  fi\n\n  local installSuccess=0\n  for variationName in \"${variations[@]}\"; do\n    local name=\"$variationName[@]\"\n    local variation=(\"${!name}\")\n    echo \"  Attempting to install $dotnetVersionLabel from $variationName.\"\n    bash \"$install_script\" \"${variation[@]}\" && installSuccess=1\n    if [[ \"$installSuccess\" -eq 1 ]]; then\n      break\n    fi\n\n    echo \"  Failed to install $dotnetVersionLabel from $variationName.\"\n  done\n\n  if [[ \"$installSuccess\" -eq 0 ]]; then\n    Write-PipelineTelemetryError -category 'InitializeToolset' \"Failed to install $dotnetVersionLabel from any of the specified locations.\"\n    ExitWithExitCode 1\n  fi\n}\n\nfunction with_retries {\n  local maxRetries=5\n  local retries=1\n  echo \"Trying to run '$@' for maximum of $maxRetries attempts.\"\n  while [[ $((retries++)) -le $maxRetries ]]; do\n    \"$@\"\n\n    if [[ $? == 0 ]]; then\n      echo \"Ran '$@' successfully.\"\n      return 0\n    fi\n\n    timeout=$((3**$retries-1))\n    echo \"Failed to execute '$@'. Waiting $timeout seconds before next attempt ($retries out of $maxRetries).\" 1>&2\n    sleep $timeout\n  done\n\n  echo \"Failed to execute '$@' for $maxRetries times.\" 1>&2\n\n  return 1\n}\n\nfunction GetDotNetInstallScript {\n  local root=$1\n  local install_script=\"$root/dotnet-install.sh\"\n  local install_script_url=\"https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh\"\n  local timestamp_file=\"$root/.dotnet-install.timestamp\"\n  local should_download=false\n\n  if [[ ! -a \"$install_script\" ]]; then\n    should_download=true\n  elif [[ -f \"$timestamp_file\" ]]; then\n    # Check if the script is older than 30 days using timestamp file\n    local download_time=$(cat \"$timestamp_file\" 2>/dev/null || echo \"0\")\n    local current_time=$(date +%s)\n    local age_seconds=$((current_time - download_time))\n    \n    # 30 days = 30 * 24 * 60 * 60 = 2592000 seconds\n    if [[ $age_seconds -gt 2592000 ]]; then\n      echo \"Existing install script is too old, re-downloading...\"\n      should_download=true\n    fi\n  else\n    # No timestamp file exists, assume script is old and re-download\n    echo \"No timestamp found for existing install script, re-downloading...\"\n    should_download=true\n  fi\n\n  if [[ \"$should_download\" == true ]]; then\n    mkdir -p \"$root\"\n\n    echo \"Downloading '$install_script_url'\"\n\n    # Use curl if available, otherwise use wget\n    if command -v curl > /dev/null; then\n      # first, try directly, if this fails we will retry with verbose logging\n      curl \"$install_script_url\" -sSL --retry 10 --create-dirs -o \"$install_script\" || {\n        if command -v openssl &> /dev/null; then\n          echo \"Curl failed; dumping some information about dotnet.microsoft.com for later investigation\"\n          echo | openssl s_client -showcerts -servername dotnet.microsoft.com  -connect dotnet.microsoft.com:443 || true\n        fi\n        echo \"Will now retry the same URL with verbose logging.\"\n        with_retries curl \"$install_script_url\" -sSL --verbose --retry 10 --create-dirs -o \"$install_script\" || {\n          local exit_code=$?\n          Write-PipelineTelemetryError -category 'InitializeToolset' \"Failed to acquire dotnet install script (exit code '$exit_code').\"\n          ExitWithExitCode $exit_code\n        }\n      }\n    else\n      with_retries wget -v -O \"$install_script\" \"$install_script_url\" || {\n        local exit_code=$?\n        Write-PipelineTelemetryError -category 'InitializeToolset' \"Failed to acquire dotnet install script (exit code '$exit_code').\"\n        ExitWithExitCode $exit_code\n      }\n    fi\n    \n    # Create timestamp file to track download time in seconds from epoch\n    date +%s > \"$timestamp_file\"\n  fi\n  # return value\n  _GetDotNetInstallScript=\"$install_script\"\n}\n\nfunction InitializeBuildTool {\n  if [[ -n \"${_InitializeBuildTool:-}\" ]]; then\n    return\n  fi\n\n  InitializeDotNetCli $restore\n\n  # return values\n  _InitializeBuildTool=\"$_InitializeDotNetCli/dotnet\"\n  _InitializeBuildToolCommand=\"msbuild\"\n}\n\nfunction GetNuGetPackageCachePath {\n  if [[ -z ${NUGET_PACKAGES:-} ]]; then\n    if [[ \"$use_global_nuget_cache\" == true ]]; then\n      export NUGET_PACKAGES=\"$HOME/.nuget/packages/\"\n    else\n      export NUGET_PACKAGES=\"$repo_root/.packages/\"\n    fi\n  fi\n\n  # return value\n  _GetNuGetPackageCachePath=$NUGET_PACKAGES\n}\n\nfunction InitializeNativeTools() {\n  if [[ -n \"${DisableNativeToolsetInstalls:-}\" ]]; then\n    return\n  fi\n  if grep -Fq \"native-tools\" $global_json_file\n  then\n    local nativeArgs=\"\"\n    if [[ \"$ci\" == true ]]; then\n      nativeArgs=\"--installDirectory $tools_dir\"\n    fi\n    \"$_script_dir/init-tools-native.sh\" $nativeArgs\n  fi\n}\n\nfunction InitializeToolset {\n  if [[ -n \"${_InitializeToolset:-}\" ]]; then\n    return\n  fi\n\n  GetNuGetPackageCachePath\n\n  ReadGlobalVersion \"Microsoft.DotNet.Arcade.Sdk\"\n\n  local toolset_version=$_ReadGlobalVersion\n  local toolset_location_file=\"$toolset_dir/$toolset_version.txt\"\n\n  if [[ -a \"$toolset_location_file\" ]]; then\n    local path=`cat \"$toolset_location_file\"`\n    if [[ -a \"$path\" ]]; then\n      # return value\n      _InitializeToolset=\"$path\"\n      return\n    fi\n  fi\n\n  if [[ \"$restore\" != true ]]; then\n    Write-PipelineTelemetryError -category 'InitializeToolset' \"Toolset version $toolset_version has not been restored.\"\n    ExitWithExitCode 2\n  fi\n\n  local proj=\"$toolset_dir/restore.proj\"\n\n  local bl=\"\"\n  if [[ \"$binary_log\" == true ]]; then\n    bl=\"/bl:$log_dir/ToolsetRestore.binlog\"\n  fi\n\n  echo '<Project Sdk=\"Microsoft.DotNet.Arcade.Sdk\"/>' > \"$proj\"\n  MSBuild-Core \"$proj\" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\\;NoSummary /p:__ToolsetLocationOutputFile=\"$toolset_location_file\"\n\n  local toolset_build_proj=`cat \"$toolset_location_file\"`\n\n  if [[ ! -a \"$toolset_build_proj\" ]]; then\n    Write-PipelineTelemetryError -category 'Build' \"Invalid toolset path: $toolset_build_proj\"\n    ExitWithExitCode 3\n  fi\n\n  # return value\n  _InitializeToolset=\"$toolset_build_proj\"\n}\n\nfunction ExitWithExitCode {\n  if [[ \"$ci\" == true && \"$prepare_machine\" == true ]]; then\n    StopProcesses\n  fi\n  exit $1\n}\n\nfunction StopProcesses {\n  echo \"Killing running build processes...\"\n  pkill -9 \"dotnet\" || true\n  pkill -9 \"vbcscompiler\" || true\n  return 0\n}\n\nfunction MSBuild {\n  local args=( \"$@\" )\n  if [[ \"$pipelines_log\" == true ]]; then\n    InitializeBuildTool\n    InitializeToolset\n\n    if [[ \"$ci\" == true ]]; then\n      export NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20\n      export NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20\n      Write-PipelineSetVariable -name \"NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS\" -value \"20\"\n      Write-PipelineSetVariable -name \"NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS\" -value \"20\"\n    fi\n\n    local toolset_dir=\"${_InitializeToolset%/*}\"\n    local selectedPath=\"$toolset_dir/net/Microsoft.DotNet.ArcadeLogging.dll\"\n\n    if [[ -z \"$selectedPath\" ]]; then\n      Write-PipelineTelemetryError -category 'Build'  \"Unable to find arcade sdk logger assembly: $selectedPath\"\n      ExitWithExitCode 1\n    fi\n\n    args+=( \"-logger:$selectedPath\" )\n  fi\n\n  MSBuild-Core \"${args[@]}\"\n}\n\nfunction MSBuild-Core {\n  if [[ \"$ci\" == true ]]; then\n    if [[ \"$binary_log\" != true && \"$exclude_ci_binary_log\" != true ]]; then\n      Write-PipelineTelemetryError -category 'Build'  \"Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch.\"\n      ExitWithExitCode 1\n    fi\n\n    if [[ \"$node_reuse\" == true ]]; then\n      Write-PipelineTelemetryError -category 'Build'  \"Node reuse must be disabled in CI build.\"\n      ExitWithExitCode 1\n    fi\n  fi\n\n  InitializeBuildTool\n\n  local warnaserror_switch=\"\"\n  if [[ $warn_as_error == true ]]; then\n    warnaserror_switch=\"/warnaserror\"\n  fi\n\n  function RunBuildTool {\n    export ARCADE_BUILD_TOOL_COMMAND=\"$_InitializeBuildTool $@\"\n\n    \"$_InitializeBuildTool\" \"$@\" || {\n      local exit_code=$?\n      # We should not Write-PipelineTaskError here because that message shows up in the build summary\n      # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.\n      echo \"Build failed with exit code $exit_code. Check errors above.\"\n\n      # When running on Azure Pipelines, override the returned exit code to avoid double logging.\n      # Skip this when the build is a child of the VMR build.\n      if [[ \"$ci\" == true && -n ${SYSTEM_TEAMPROJECT:-} && \"$from_vmr\" != true ]]; then\n        Write-PipelineSetResult -result \"Failed\" -message \"msbuild execution failed.\"\n        # Exiting with an exit code causes the azure pipelines task to log yet another \"noise\" error\n        # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error\n        ExitWithExitCode 0\n      else\n        ExitWithExitCode $exit_code\n      fi\n    }\n  }\n\n  # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable\n  local mt_switch=\"\"\n  if [[ \"${MSBUILD_MT_ENABLED:-}\" == \"1\" ]]; then\n    mt_switch=\"-mt\"\n  fi\n\n  RunBuildTool \"$_InitializeBuildToolCommand\" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch $mt_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci \"$@\"\n}\n\nfunction GetDarc {\n    darc_path=\"$temp_dir/darc\"\n    version=\"$1\"\n\n    if [[ -n \"$version\" ]]; then\n      version=\"--darcversion $version\"\n    fi\n\n    \"$eng_root/common/darc-init.sh\" --toolpath \"$darc_path\" $version\n    darc_tool=\"$darc_path/darc\"\n}\n\n# Returns a full path to an Arcade SDK task project file.\nfunction GetSdkTaskProject {\n  taskName=$1\n  echo \"$(dirname $_InitializeToolset)/SdkTasks/$taskName.proj\"\n}\n\nResolvePath \"${BASH_SOURCE[0]}\"\n_script_dir=`dirname \"$_ResolvePath\"`\n\n. \"$_script_dir/pipeline-logging-functions.sh\"\n\neng_root=`cd -P \"$_script_dir/..\" && pwd`\nrepo_root=`cd -P \"$_script_dir/../..\" && pwd`\nrepo_root=\"${repo_root}/\"\nartifacts_dir=\"${repo_root}artifacts\"\ntoolset_dir=\"$artifacts_dir/toolset\"\ntools_dir=\"${repo_root}.tools\"\nlog_dir=\"$artifacts_dir/log/$configuration\"\ntemp_dir=\"$artifacts_dir/tmp/$configuration\"\n\nglobal_json_file=\"${repo_root}global.json\"\n# determine if global.json contains a \"runtimes\" entry\nglobal_json_has_runtimes=false\nif command -v jq &> /dev/null; then\n  if jq -e '.tools | has(\"runtimes\")' \"$global_json_file\" &> /dev/null; then\n    global_json_has_runtimes=true\n  fi\nelif [[ \"$(cat \"$global_json_file\")\" =~ \\\"runtimes\\\"[[:space:]\\:]*\\{ ]]; then\n  global_json_has_runtimes=true\nfi\n\n# HOME may not be defined in some scenarios, but it is required by NuGet\nif [[ -z $HOME ]]; then\n  export HOME=\"${repo_root}artifacts/.home/\"\n  mkdir -p \"$HOME\"\nfi\n\nmkdir -p \"$toolset_dir\"\nmkdir -p \"$temp_dir\"\nmkdir -p \"$log_dir\"\n\nWrite-PipelineSetVariable -name \"Artifacts\" -value \"$artifacts_dir\"\nWrite-PipelineSetVariable -name \"Artifacts.Toolset\" -value \"$toolset_dir\"\nWrite-PipelineSetVariable -name \"Artifacts.Log\" -value \"$log_dir\"\nWrite-PipelineSetVariable -name \"Temp\" -value \"$temp_dir\"\nWrite-PipelineSetVariable -name \"TMP\" -value \"$temp_dir\"\n\n# Import custom tools configuration, if present in the repo.\nif [ -z \"${disable_configure_toolset_import:-}\" ]; then\n  configure_toolset_script=\"$eng_root/configure-toolset.sh\"\n  if [[ -a \"$configure_toolset_script\" ]]; then\n    . \"$configure_toolset_script\"\n  fi\nfi\n\n# TODO: https://github.com/dotnet/arcade/issues/1468\n# Temporary workaround to avoid breaking change.\n# Remove once repos are updated.\nif [[ -n \"${useInstalledDotNetCli:-}\" ]]; then\n  use_installed_dotnet_cli=\"$useInstalledDotNetCli\"\nfi\n"
  },
  {
    "path": "eng/common/vmr-sync.ps1",
    "content": "<#\n.SYNOPSIS\n\nThis script is used for synchronizing the current repository into a local VMR.\nIt pulls the current repository's code into the specified VMR directory for local testing or\nSource-Build validation.\n\n.DESCRIPTION\n\nThe tooling used for synchronization will clone the VMR repository into a temporary folder if\nit does not already exist. These clones can be reused in future synchronizations, so it is\nrecommended to dedicate a folder for this to speed up re-runs.\n\n.EXAMPLE\n  Synchronize current repository into a local VMR:\n    ./vmr-sync.ps1 -vmrDir \"$HOME/repos/dotnet\" -tmpDir \"$HOME/repos/tmp\"\n\n.PARAMETER tmpDir\nRequired. Path to the temporary folder where repositories will be cloned\n\n.PARAMETER vmrBranch\nOptional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch\n\n.PARAMETER azdevPat\nOptional. Azure DevOps PAT to use for cloning private repositories.\n\n.PARAMETER vmrDir\nOptional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder\n\n.PARAMETER debugOutput\nOptional. Enables debug logging in the darc vmr command.\n\n.PARAMETER ci\nOptional. Denotes that the script is running in a CI environment.\n#>\nparam (\n  [Parameter(Mandatory=$true, HelpMessage=\"Path to the temporary folder where repositories will be cloned\")]\n  [string][Alias('t', 'tmp')]$tmpDir,\n  [string][Alias('b', 'branch')]$vmrBranch,\n  [string]$remote,\n  [string]$azdevPat,\n  [string][Alias('v', 'vmr')]$vmrDir,\n  [switch]$ci,\n  [switch]$debugOutput\n)\n\nfunction Fail {\n  Write-Host \"> $($args[0])\" -ForegroundColor 'Red'\n}\n\nfunction Highlight {\n  Write-Host \"> $($args[0])\" -ForegroundColor 'Cyan'\n}\n\n$verbosity = 'verbose'\nif ($debugOutput) {\n  $verbosity = 'debug'\n}\n# Validation\n\nif (-not $tmpDir) {\n  Fail \"Missing -tmpDir argument. Please specify the path to the temporary folder where the repositories will be cloned\"\n  exit 1\n}\n\n# Sanitize the input\n\nif (-not $vmrDir) {\n  $vmrDir = Join-Path $tmpDir 'dotnet'\n}\n\nif (-not (Test-Path -Path $tmpDir -PathType Container)) {\n  New-Item -ItemType Directory -Path $tmpDir | Out-Null\n}\n\n# Prepare the VMR\n\nif (-not (Test-Path -Path $vmrDir -PathType Container)) {\n  Highlight \"Cloning 'dotnet/dotnet' into $vmrDir..\"\n  git clone https://github.com/dotnet/dotnet $vmrDir\n\n  if ($vmrBranch) {\n    git -C $vmrDir switch -c $vmrBranch\n  }\n}\nelse {\n  if ((git -C $vmrDir diff --quiet) -eq $false) {\n    Fail \"There are changes in the working tree of $vmrDir. Please commit or stash your changes\"\n    exit 1\n  }\n\n  if ($vmrBranch) {\n    Highlight \"Preparing $vmrDir\"\n    git -C $vmrDir checkout $vmrBranch\n    git -C $vmrDir pull\n  }\n}\n\nSet-StrictMode -Version Latest\n\n# Prepare darc\n\nHighlight 'Installing .NET, preparing the tooling..'\n. .\\eng\\common\\tools.ps1\n$dotnetRoot = InitializeDotNetCli -install:$true\n$env:DOTNET_ROOT = $dotnetRoot\n$darc = Get-Darc\n\nHighlight \"Starting the synchronization of VMR..\"\n\n# Synchronize the VMR\n$versionDetailsPath = Resolve-Path (Join-Path $PSScriptRoot '..\\Version.Details.xml') | Select-Object -ExpandProperty Path\n[xml]$versionDetails = Get-Content -Path $versionDetailsPath\n$repoName = $versionDetails.SelectSingleNode('//Source').Mapping\nif (-not $repoName) {\n  Fail \"Failed to resolve repo mapping from $versionDetailsPath\"\n  exit 1\n}\n\n$darcArgs = (\n  \"vmr\", \"forwardflow\",\n  \"--tmp\", $tmpDir,\n  \"--$verbosity\",\n  $vmrDir\n)\n\nif ($ci) {\n  $darcArgs += (\"--ci\")\n}\n\nif ($azdevPat) {\n  $darcArgs += (\"--azdev-pat\", $azdevPat)\n}\n\n& \"$darc\" $darcArgs\n\nif ($LASTEXITCODE -eq 0) {\n  Highlight \"Synchronization succeeded\"\n}\nelse {\n  Highlight \"Failed to flow code into the local VMR. Falling back to resetting the VMR to match repo contents...\"\n  git -C $vmrDir reset --hard\n\n  $resetArgs = (\n    \"vmr\", \"reset\",\n    \"${repoName}:HEAD\",\n    \"--vmr\", $vmrDir,\n    \"--tmp\", $tmpDir,\n    \"--additional-remotes\", \"${repoName}:${repoRoot}\"\n  )\n\n  & \"$darc\" $resetArgs\n\n  if ($LASTEXITCODE -eq 0) {\n    Highlight \"Successfully reset the VMR using 'darc vmr reset'\"\n  }\n  else {\n    Fail \"Synchronization of repo to VMR failed!\"\n    Fail \"'$vmrDir' is left in its last state (re-run of this script will reset it).\"\n    Fail \"Please inspect the logs which contain path to the failing patch file (use -debugOutput to get all the details).\"\n    Fail \"Once you make changes to the conflicting VMR patch, commit it locally and re-run this script.\"\n    exit 1\n  }\n}\n"
  },
  {
    "path": "eng/common/vmr-sync.sh",
    "content": "#!/bin/bash\n\n### This script is used for synchronizing the current repository into a local VMR.\n### It pulls the current repository's code into the specified VMR directory for local testing or\n### Source-Build validation.\n###\n### The tooling used for synchronization will clone the VMR repository into a temporary folder if\n### it does not already exist. These clones can be reused in future synchronizations, so it is\n### recommended to dedicate a folder for this to speed up re-runs.\n###\n### USAGE:\n###   Synchronize current repository into a local VMR:\n###     ./vmr-sync.sh --tmp \"$HOME/repos/tmp\" \"$HOME/repos/dotnet\"\n###\n### Options:\n###   -t, --tmp, --tmp-dir PATH\n###       Required. Path to the temporary folder where repositories will be cloned\n###\n###   -b, --branch, --vmr-branch BRANCH_NAME\n###       Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch\n###\n###   --debug\n###       Optional. Turns on the most verbose logging for the VMR tooling\n###\n###   --remote name:URI\n###       Optional. Additional remote to use during the synchronization\n###       This can be used to synchronize to a commit from a fork of the repository\n###       Example: 'runtime:https://github.com/yourfork/runtime'\n###\n###   --azdev-pat\n###       Optional. Azure DevOps PAT to use for cloning private repositories.\n###\n###   -v, --vmr, --vmr-dir PATH\n###       Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder\n\nsource=\"${BASH_SOURCE[0]}\"\n\n# resolve $source until the file is no longer a symlink\nwhile [[ -h \"$source\" ]]; do\n  scriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n  source=\"$(readlink \"$source\")\"\n  # if $source was a relative symlink, we need to resolve it relative to the path where the\n  # symlink file was located\n  [[ $source != /* ]] && source=\"$scriptroot/$source\"\ndone\nscriptroot=\"$( cd -P \"$( dirname \"$source\" )\" && pwd )\"\n\nfunction print_help () {\n    sed -n '/^### /,/^$/p' \"$source\" | cut -b 5-\n}\n\nCOLOR_RED=$(tput setaf 1 2>/dev/null || true)\nCOLOR_CYAN=$(tput setaf 6 2>/dev/null || true)\nCOLOR_CLEAR=$(tput sgr0 2>/dev/null || true)\nCOLOR_RESET=uniquesearchablestring\nFAILURE_PREFIX='> '\n\nfunction fail () {\n  echo \"${COLOR_RED}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_RED}}${COLOR_CLEAR}\" >&2\n}\n\nfunction highlight () {\n  echo \"${COLOR_CYAN}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_CYAN}}${COLOR_CLEAR}\"\n}\n\ntmp_dir=''\nvmr_dir=''\nvmr_branch=''\nadditional_remotes=''\nverbosity=verbose\nazdev_pat=''\nci=false\n\nwhile [[ $# -gt 0 ]]; do\n  opt=\"$(echo \"$1\" | tr \"[:upper:]\" \"[:lower:]\")\"\n  case \"$opt\" in\n    -t|--tmp|--tmp-dir)\n      tmp_dir=$2\n      shift\n      ;;\n    -v|--vmr|--vmr-dir)\n      vmr_dir=$2\n      shift\n      ;;\n    -b|--branch|--vmr-branch)\n      vmr_branch=$2\n      shift\n      ;;\n    --remote)\n      additional_remotes=\"$additional_remotes $2\"\n      shift\n      ;;\n    --azdev-pat)\n      azdev_pat=$2\n      shift\n      ;;\n    --ci)\n      ci=true\n      ;;\n    -d|--debug)\n      verbosity=debug\n      ;;\n    -h|--help)\n      print_help\n      exit 0\n      ;;\n    *)\n      fail \"Invalid argument: $1\"\n      print_help\n      exit 1\n      ;;\n  esac\n\n  shift\ndone\n\n# Validation\n\nif [[ -z \"$tmp_dir\" ]]; then\n  fail \"Missing --tmp-dir argument. Please specify the path to the temporary folder where the repositories will be cloned\"\n  exit 1\nfi\n\n# Sanitize the input\n\nif [[ -z \"$vmr_dir\" ]]; then\n  vmr_dir=\"$tmp_dir/dotnet\"\nfi\n\nif [[ ! -d \"$tmp_dir\" ]]; then\n  mkdir -p \"$tmp_dir\"\nfi\n\nif [[ \"$verbosity\" == \"debug\" ]]; then\n  set -x\nfi\n\n# Prepare the VMR\n\nif [[ ! -d \"$vmr_dir\" ]]; then\n  highlight \"Cloning 'dotnet/dotnet' into $vmr_dir..\"\n  git clone https://github.com/dotnet/dotnet \"$vmr_dir\"\n\n  if [[ -n \"$vmr_branch\" ]]; then\n    git -C \"$vmr_dir\" switch -c \"$vmr_branch\"\n  fi\nelse\n  if ! git -C \"$vmr_dir\" diff --quiet; then\n    fail \"There are changes in the working tree of $vmr_dir. Please commit or stash your changes\"\n    exit 1\n  fi\n\n  if [[ -n \"$vmr_branch\" ]]; then\n    highlight \"Preparing $vmr_dir\"\n    git -C \"$vmr_dir\" checkout \"$vmr_branch\"\n    git -C \"$vmr_dir\" pull\n  fi\nfi\n\nset -e\n\n# Prepare darc\n\nhighlight 'Installing .NET, preparing the tooling..'\nsource \"./eng/common/tools.sh\"\nInitializeDotNetCli true\nGetDarc\ndotnetDir=$( cd ./.dotnet/; pwd -P )\ndotnet=$dotnetDir/dotnet\n\nhighlight \"Starting the synchronization of VMR..\"\nset +e\n\nif [[ -n \"$additional_remotes\" ]]; then\n  additional_remotes=\"--additional-remotes $additional_remotes\"\nfi\n\nif [[ -n \"$azdev_pat\" ]]; then\n  azdev_pat=\"--azdev-pat $azdev_pat\"\nfi\n\nci_arg=''\nif [[ \"$ci\" == \"true\" ]]; then\n  ci_arg=\"--ci\"\nfi\n\n# Synchronize the VMR\n\nversion_details_path=$(cd \"$scriptroot/..\"; pwd -P)/Version.Details.xml\nrepo_name=$(grep -m 1 '<Source ' \"$version_details_path\" | sed -n 's/.*Mapping=\"\\([^\"]*\\)\".*/\\1/p')\nif [[ -z \"$repo_name\" ]]; then\n  fail \"Failed to resolve repo mapping from $version_details_path\"\n  exit 1\nfi\n\nexport DOTNET_ROOT=\"$dotnetDir\"\n\n\"$darc_tool\" vmr forwardflow \\\n  --tmp \"$tmp_dir\"             \\\n  $azdev_pat                   \\\n  --$verbosity                 \\\n  $ci_arg                      \\\n  $additional_remotes          \\\n  \"$vmr_dir\"\n\nif [[ $? == 0 ]]; then\n  highlight \"Synchronization succeeded\"\nelse\n  highlight \"Failed to flow code into the local VMR. Falling back to resetting the VMR to match repo contents...\"\n  git -C \"$vmr_dir\" reset --hard\n\n  \"$darc_tool\" vmr reset \\\n    \"$repo_name:HEAD\"                              \\\n    --vmr \"$vmr_dir\"                               \\\n    --tmp \"$tmp_dir\"                               \\\n    --additional-remotes \"$repo_name:$repo_root\"\n\n  if [[ $? == 0 ]]; then\n    highlight \"Successfully reset the VMR using 'darc vmr reset'\"\n  else\n    fail \"Synchronization of repo to VMR failed!\"\n    fail \"'$vmr_dir' is left in its last state (re-run of this script will reset it).\"\n    fail \"Please inspect the logs which contain path to the failing patch file (use --debug to get all the details).\"\n    fail \"Once you make changes to the conflicting VMR patch, commit it locally and re-run this script.\"\n    exit 1\n  fi\nfi\n"
  },
  {
    "path": "es-metadata.yml",
    "content": "schemaVersion: 1.0.0\nproviders:\n- provider: InventoryAsCode\n  version: 1.0.0\n  metadata:\n    isProduction: true\n    accountableOwners:\n      service: b3b0bec4-5d05-420a-a013-d3162931ee4a\n    routing:\n      defaultAreaPath:\n        org: devdiv\n        path: DevDiv\\NET Tools\\sign\n"
  },
  {
    "path": "global.json",
    "content": "{\n  \"tools\": {\n    \"_comment\": \"Because this affects the runtime environment of Sign CLI *when run from this directory*, the dotnet and runtime properties should reference the latest .NET SDK and runtime versions for Sign CLI's target framework, which is specified in Directory.Build.props.  However, the SDK and runtime versions are currently out of sync because of vulnerabilities in older versions of xcopy-msbuild.\",\n    \"dotnet\": \"10.0.106\",\n    \"runtimes\": {\n      \"dotnet/x64\": [\n        \"8.0.22\"\n      ]\n    },\n    \"xcopy-msbuild\": \"18.0.0\"\n  },\n  \"sdk\": {\n    \"version\": \"10.0.106\",\n    \"rollForward\": \"latestFeature\"\n  },\n  \"msbuild-sdks\": {\n    \"Microsoft.DotNet.Arcade.Sdk\": \"10.0.0-beta.26222.2\",\n    \"Microsoft.DotNet.Helix.Sdk\": \"10.0.0-beta.24555.3\",\n    \"Microsoft.Build.NoTargets\": \"3.7.0\"\n  }\n}\n"
  },
  {
    "path": "scripts/UpdateWintrust.ps1",
    "content": "param(\n    [string] $WintrustIniPath\n)\n\n# Test if the Wintrust.ini file exists\nif (!(Test-Path $WintrustIniPath -PathType Leaf)) {\n    exit 1\n}\n\n$wintrustini = Get-Content $WintrustIniPath -Raw\n\n# Update the Wintrust.ini file to include the NavSIP.dll\n$navSipIni = @'\n\n\n[5]\nDLL=NavSip.dll\nGUID={36FFA03E-F824-48E7-8E07-4A2DCB034CC7}\nCryptSIPDllCreateIndirectData=NavSIPCreateIndirectData\nCryptSIPDllGetSignedDataMsg=NavSIPGetSignedDataMsg\nCryptSIPDllIsMyFileType2=NavSIPIsFileSupportedName\nCryptSIPDllPutSignedDataMsg=NavSIPPutSignedDataMsg\nCryptSIPDllRemoveSignedDataMsg=NavSIPRemoveSignedDataMsg\nCryptSIPDllVerifyIndirectData=NavSIPVerifyIndirectData\n'@\n\nif ($wintrustini -notmatch 'NavSip.dll') {\n    Write-Host \"Adding NavSip.dll to wintrust.dll.ini - $WintrustIniPath\"\n    $wintrustini += $navSipIni\n    Set-Content -Path $WintrustIniPath -Value $wintrustini\n}"
  },
  {
    "path": "scripts/VerifyNuGetPackage.ps1",
    "content": "﻿param\n(\n    [Parameter(Mandatory = $True)]\n    [string] $PackageDirectoryPath\n)\n\nAdd-Type -AssemblyName 'System.IO.Compression'\n\n[int] $ErrorExitCode = 1\n\nFunction VerifyPackage([System.IO.FileInfo] $packageFile, [string[]] $expectedEntryFullNames)\n{\n    [System.IO.FileStream] $stream = $packageFile.OpenRead()\n\n    Try\n    {\n        $zipArchive = New-Object System.IO.Compression.ZipArchive -ArgumentList @($stream, [System.IO.Compression.ZipArchiveMode]::Read)\n\n        Try\n        {\n            ForEach ($expectedEntryFullName in $expectedEntryFullNames)\n            {\n                [System.IO.Compression.ZipArchiveEntry] $actualEntry = $zipArchive.GetEntry($expectedEntryFullName)\n\n                If ($actualEntry)\n                {\n                    Write-Host \"The NuGet package contains $expectedEntryFullName\"\n                }\n                Else\n                {\n                    Throw \"The NuGet package does not contain $expectedEntryFullName\"\n                }\n            }\n        }\n        Finally\n        {\n            $zipArchive.Dispose()\n        }\n    }\n    Finally\n    {\n        $stream.Dispose()\n    }\n}\n\n[string[]] $packageFilePaths = [System.IO.Directory]::GetFiles($PackageDirectoryPath, '*.nupkg')\n\nIf ($packageFilePaths.Count -ne 1)\n{\n    Write-Error \"Exactly one package was expected (but not found) in $PackageDirectoryPath\"\n\n    Exit $ErrorExitCode\n}\n\n[string] $sourcePackageFilePath = $packageFilePaths[0]\n[System.IO.FileInfo] $destinationFile = [System.IO.FileInfo]::new(\n    [System.IO.Path]::Combine(\n        [System.IO.Path]::GetTempPath(),\n        \"$([System.IO.Path]::GetRandomFileName()).zip\"))\n[bool] $overwrite = $True\n[System.IO.File]::Copy($sourcePackageFilePath, $destinationFile.FullName, $overwrite)\n\n[string[]] $expectedEntryFullNames =\n    'tools/net8.0/any/sign.dll',\n    'tools/net8.0/any/tools/SDK/x64/appxpackaging.dll',\n    'tools/net8.0/any/tools/SDK/x64/appxsip.dll',\n    'tools/net8.0/any/tools/SDK/x64/makeappx.exe',\n    'tools/net8.0/any/tools/SDK/x64/makepri.exe',\n    'tools/net8.0/any/tools/SDK/x64/Microsoft.Windows.Build.Appx.AppxPackaging.dll.manifest',\n    'tools/net8.0/any/tools/SDK/x64/Microsoft.Windows.Build.Appx.AppxSip.dll.manifest',\n    'tools/net8.0/any/tools/SDK/x64/Microsoft.Windows.Build.Appx.OpcServices.dll.manifest',\n    'tools/net8.0/any/tools/SDK/x64/Microsoft.Windows.Build.Signing.mssign32.dll.manifest',\n    'tools/net8.0/any/tools/SDK/x64/Microsoft.Windows.Build.Signing.wintrust.dll.manifest',\n    'tools/net8.0/any/tools/SDK/x64/mssign32.dll',\n    'tools/net8.0/any/tools/SDK/x64/NavSip.dll',\n    'tools/net8.0/any/tools/SDK/x64/opcservices.dll',\n    'tools/net8.0/any/tools/SDK/x64/SignTool.exe.manifest',\n    'tools/net8.0/any/tools/SDK/x64/wintrust.dll',\n    'tools/net8.0/any/tools/SDK/x64/wintrust.dll.ini',\n    'tools/net8.0/any/tools/SDK/x86/mage.exe'\n\nTry\n{\n    VerifyPackage -packageFile $destinationFile -expectedEntryFullNames $expectedEntryFullNames\n}\nCatch\n{\n    Write-Error $_.Exception.Message\n\n    Exit $ErrorExitCode\n}\nFinally\n{\n    $destinationFile.Delete()\n}"
  },
  {
    "path": "sign.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.5.33017.460\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{3E52C226-1DA9-4712-AC4E-A8820473DDA8}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.editorconfig = .editorconfig\n\t\t.gitattributes = .gitattributes\n\t\t.gitignore = .gitignore\n\t\t.vsts-ci.yml = .vsts-ci.yml\n\t\t.vsts-pr.yml = .vsts-pr.yml\n\t\tCODE-OF-CONDUCT.md = CODE-OF-CONDUCT.md\n\t\tDirectory.Build.props = Directory.Build.props\n\t\tDirectory.Build.targets = Directory.Build.targets\n\t\tDirectory.Packages.props = Directory.Packages.props\n\t\tglobal.json = global.json\n\t\tNuGet.Config = NuGet.Config\n\t\tSdkTools.props = SdkTools.props\n\t\tSECURITY.md = SECURITY.md\n\t\t.github\\workflows\\stale.yml = .github\\workflows\\stale.yml\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.Core\", \"src\\Sign.Core\\Sign.Core.csproj\", \"{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{780818DD-6B52-47C8-AC54-71448DF822BD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.Core.Test\", \"test\\Sign.Core.Test\\Sign.Core.Test.csproj\", \"{67DCC7B7-C98D-452E-AE69-1F3E81833D34}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.Cli\", \"src\\Sign.CLI\\Sign.Cli.csproj\", \"{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.Cli.Test\", \"test\\Sign.Cli.Test\\Sign.Cli.Test.csproj\", \"{3C6FC0EB-F5B9-430C-B420-4DEC6B390768}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.KeyVault\", \"src\\Sign.SignatureProviders.KeyVault\\Sign.SignatureProviders.KeyVault.csproj\", \"{5B69CC06-5CBA-4A0B-B262-76ABF01542AC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.KeyVault.Test\", \"test\\Sign.SignatureProviders.KeyVault.Test\\Sign.SignatureProviders.KeyVault.Test.csproj\", \"{2EF3535D-E359-4211-98AB-FC992815355E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.TestInfrastructure\", \"test\\Sign.TestInfrastructure\\Sign.TestInfrastructure.csproj\", \"{47F03ADD-A646-44C8-92FA-9594CD4506E6}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.CertificateStore\", \"src\\Sign.SignatureProviders.CertificateStore\\Sign.SignatureProviders.CertificateStore.csproj\", \"{68104303-9832-4841-89AB-B98712C4E618}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.CertificateStore.Test\", \"test\\Sign.SignatureProviders.CertificateStore.Test\\Sign.SignatureProviders.CertificateStore.Test.csproj\", \"{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.ArtifactSigning\", \"src\\Sign.SignatureProviders.ArtifactSigning\\Sign.SignatureProviders.ArtifactSigning.csproj\", \"{060800AF-42FC-493C-AD99-9C87212BA969}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sign.SignatureProviders.ArtifactSigning.Test\", \"test\\Sign.SignatureProviders.ArtifactSigning.Test\\Sign.SignatureProviders.ArtifactSigning.Test.csproj\", \"{A81695AF-088A-436A-9A38-4D0B0DB2D826}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{67DCC7B7-C98D-452E-AE69-1F3E81833D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67DCC7B7-C98D-452E-AE69-1F3E81833D34}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{67DCC7B7-C98D-452E-AE69-1F3E81833D34}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{67DCC7B7-C98D-452E-AE69-1F3E81833D34}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3C6FC0EB-F5B9-430C-B420-4DEC6B390768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3C6FC0EB-F5B9-430C-B420-4DEC6B390768}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3C6FC0EB-F5B9-430C-B420-4DEC6B390768}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3C6FC0EB-F5B9-430C-B420-4DEC6B390768}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5B69CC06-5CBA-4A0B-B262-76ABF01542AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B69CC06-5CBA-4A0B-B262-76ABF01542AC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B69CC06-5CBA-4A0B-B262-76ABF01542AC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B69CC06-5CBA-4A0B-B262-76ABF01542AC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2EF3535D-E359-4211-98AB-FC992815355E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2EF3535D-E359-4211-98AB-FC992815355E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2EF3535D-E359-4211-98AB-FC992815355E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2EF3535D-E359-4211-98AB-FC992815355E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{47F03ADD-A646-44C8-92FA-9594CD4506E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{47F03ADD-A646-44C8-92FA-9594CD4506E6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{47F03ADD-A646-44C8-92FA-9594CD4506E6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{47F03ADD-A646-44C8-92FA-9594CD4506E6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{68104303-9832-4841-89AB-B98712C4E618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{68104303-9832-4841-89AB-B98712C4E618}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{68104303-9832-4841-89AB-B98712C4E618}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{68104303-9832-4841-89AB-B98712C4E618}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{060800AF-42FC-493C-AD99-9C87212BA969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{060800AF-42FC-493C-AD99-9C87212BA969}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{060800AF-42FC-493C-AD99-9C87212BA969}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{060800AF-42FC-493C-AD99-9C87212BA969}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A81695AF-088A-436A-9A38-4D0B0DB2D826}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A81695AF-088A-436A-9A38-4D0B0DB2D826}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A81695AF-088A-436A-9A38-4D0B0DB2D826}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A81695AF-088A-436A-9A38-4D0B0DB2D826}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{8781DB2C-CF89-456D-BE9D-D7EF8333F5EC} = {92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\n\t\t{67DCC7B7-C98D-452E-AE69-1F3E81833D34} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\t\t{A54EAFBE-AB23-48F7-86C5-C91ACEEDF509} = {92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\n\t\t{3C6FC0EB-F5B9-430C-B420-4DEC6B390768} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\t\t{5B69CC06-5CBA-4A0B-B262-76ABF01542AC} = {92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\n\t\t{2EF3535D-E359-4211-98AB-FC992815355E} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\t\t{47F03ADD-A646-44C8-92FA-9594CD4506E6} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\t\t{68104303-9832-4841-89AB-B98712C4E618} = {92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\n\t\t{3AE48DC2-8422-4E3A-AFBC-12551D50DBCA} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\t\t{060800AF-42FC-493C-AD99-9C87212BA969} = {92C73EE1-4EF3-4721-B6A9-9F458A673CA3}\n\t\t{A81695AF-088A-436A-9A38-4D0B0DB2D826} = {780818DD-6B52-47C8-AC54-71448DF822BD}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {7AA1043F-37A2-404F-8EC3-34C747C1CEB7}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Sign.Cli/ArtifactSigningCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Azure.CodeSigning;\nusing Azure.CodeSigning.Extensions;\nusing Azure.Core;\nusing Microsoft.Extensions.Azure;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\nusing Sign.SignatureProviders.ArtifactSigning;\n\nnamespace Sign.Cli\n{\n    internal sealed class ArtifactSigningCommand : Command\n    {\n        internal Option<Uri> EndpointOption { get; }\n        internal Option<string> AccountOption { get; }\n        internal Option<string> CertificateProfileOption { get; }\n        internal AzureCredentialOptions AzureCredentialOptions { get; } = new();\n\n        internal Argument<List<string>?> FilesArgument { get; }\n\n        internal ArtifactSigningCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)\n            : base(\"artifact-signing\", ArtifactSigningResources.CommandDescription)\n        {\n            ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));\n            ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));\n\n            EndpointOption = new Option<Uri>(\"--artifact-signing-endpoint\", \"-ase\")\n            {\n                CustomParser = CodeCommand.ParseHttpsUrl,\n                Description = ArtifactSigningResources.EndpointOptionDescription,\n                Required = true\n            };\n            AccountOption = new Option<string>(\"--artifact-signing-account\", \"-asa\")\n            {\n                Description = ArtifactSigningResources.AccountOptionDescription,\n                Required = true\n            };\n            CertificateProfileOption = new Option<string>(\"--artifact-signing-certificate-profile\", \"-ascp\")\n            {\n                Description = ArtifactSigningResources.CertificateProfileOptionDescription,\n                Required = true\n            };\n            FilesArgument = new Argument<List<string>?>(\"file(s)\")\n            {\n                Description = Resources.FilesArgumentDescription,\n                Arity = ArgumentArity.OneOrMore\n            };\n\n            Options.Add(EndpointOption);\n            Options.Add(AccountOption);\n            Options.Add(CertificateProfileOption);\n            AzureCredentialOptions.AddOptionsToCommand(this);\n\n            Arguments.Add(FilesArgument);\n\n            SetAction((ParseResult parseResult, CancellationToken cancellationToken) =>\n            {\n                List<string>? filesArgument = parseResult.GetValue(FilesArgument);\n\n                if (filesArgument is not { Count: > 0 })\n                {\n                    Console.Error.WriteLine(Resources.MissingFileValue);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                TokenCredential? credential = AzureCredentialOptions.CreateTokenCredential(parseResult);\n\n                if (credential is null)\n                {\n                    return Task.FromResult(ExitCode.Failed);\n                }\n\n                // Some of the options are required and that is why we can safely use\n                // the null-forgiving operator (!) to simplify the code.\n                Uri endpointUrl = parseResult.GetValue(EndpointOption)!;\n                string accountName = parseResult.GetValue(AccountOption)!;\n                string certificateProfileName = parseResult.GetValue(CertificateProfileOption)!;\n\n                serviceProviderFactory.AddServices(services =>\n                {\n                    services.AddAzureClients(builder =>\n                    {\n                        builder.AddCertificateProfileClient(endpointUrl);\n                        builder.UseCredential(credential);\n                        builder.ConfigureDefaults(options => options.Retry.Mode = RetryMode.Exponential);\n                    });\n\n                    services.AddSingleton(serviceProvider =>\n                    {\n                        return new ArtifactSigningService(\n                            serviceProvider.GetRequiredService<CertificateProfileClient>(),\n                            accountName,\n                            certificateProfileName,\n                            serviceProvider.GetRequiredService<ILogger<ArtifactSigningService>>());\n                    });\n                });\n\n                ArtifactSigningServiceProvider trustedSigningServiceProvider = new();\n\n                return codeCommand.HandleAsync(parseResult, serviceProviderFactory, trustedSigningServiceProvider, filesArgument);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/ArtifactSigningResources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Cli {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class ArtifactSigningResources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal ArtifactSigningResources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Cli.ArtifactSigningResources\", typeof(ArtifactSigningResources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Artifact Signing Account name..\n        /// </summary>\n        internal static string AccountOptionDescription {\n            get {\n                return ResourceManager.GetString(\"AccountOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Certificate Profile name..\n        /// </summary>\n        internal static string CertificateProfileOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateProfileOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use Artifact Signing..\n        /// </summary>\n        internal static string CommandDescription {\n            get {\n                return ResourceManager.GetString(\"CommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in..\n        /// </summary>\n        internal static string EndpointOptionDescription {\n            get {\n                return ResourceManager.GetString(\"EndpointOptionDescription\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/ArtifactSigningResources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"AccountOptionDescription\" xml:space=\"preserve\">\n    <value>The Artifact Signing Account name.</value>\n  </data>\n  <data name=\"CertificateProfileOptionDescription\" xml:space=\"preserve\">\n    <value>The Certificate Profile name.</value>\n  </data>\n  <data name=\"CommandDescription\" xml:space=\"preserve\">\n    <value>Use Artifact Signing.</value>\n  </data>\n  <data name=\"EndpointOptionDescription\" xml:space=\"preserve\">\n    <value>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.Cli/AzureCredentialOptions.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Azure.Core;\nusing Azure.Identity;\n\nnamespace Sign.Cli\n{\n    internal sealed class AzureCredentialOptions\n    {\n        internal Option<string?> CredentialTypeOption { get; }\n        internal Option<string?> ManagedIdentityClientIdOption { get; }\n        internal Option<string?> ManagedIdentityResourceIdOption { get; }\n        internal Option<bool?> ObsoleteManagedIdentityOption { get; }\n        internal Option<string?> ObsoleteTenantIdOption { get; }\n        internal Option<string?> ObsoleteClientIdOption { get; }\n        internal Option<string?> ObsoleteClientSecretOption { get; }\n\n        internal AzureCredentialOptions()\n        {\n            CredentialTypeOption = new Option<string?>(\"--azure-credential-type\", \"-act\")\n            {\n                Description = Resources.CredentialTypeOptionDescription\n            };\n            CredentialTypeOption.AcceptOnlyFromAmong(\n                AzureCredentialType.AzureCli,\n                AzureCredentialType.AzurePowerShell,\n                AzureCredentialType.ManagedIdentity,\n                AzureCredentialType.WorkloadIdentity);\n\n            ManagedIdentityClientIdOption = new Option<string?>(\"--managed-identity-client-id\", \"-mici\")\n            {\n                Description = Resources.ManagedIdentityClientIdOptionDescription\n            };\n            ManagedIdentityResourceIdOption = new Option<string?>(\"--managed-identity-resource-id\", \"-miri\")\n            {\n                Description = Resources.ManagedIdentityResourceIdOptionDescription\n            };\n            ObsoleteManagedIdentityOption = new Option<bool?>(\"--azure-key-vault-managed-identity\", \"-kvm\")\n            {\n                Description = Resources.ManagedIdentityOptionDescription,\n                Hidden = true\n            };\n            ObsoleteTenantIdOption = new Option<string?>(\"--azure-key-vault-tenant-id\", \"-kvt\")\n            {\n                Description = Resources.TenantIdOptionDescription,\n                Hidden = true\n            };\n            ObsoleteClientIdOption = new Option<string?>(\"--azure-key-vault-client-id\", \"-kvi\")\n            {\n                Description = Resources.ClientIdOptionDescription,\n                Hidden = true\n            };\n            ObsoleteClientSecretOption = new Option<string?>(\"--azure-key-vault-client-secret\", \"-kvs\")\n            {\n                Description = Resources.ClientSecretOptionDescription,\n                Hidden = true\n            };\n        }\n\n        internal void AddOptionsToCommand(Command command)\n        {\n            command.Options.Add(CredentialTypeOption);\n            command.Options.Add(ManagedIdentityClientIdOption);\n            command.Options.Add(ManagedIdentityResourceIdOption);\n            command.Options.Add(ObsoleteManagedIdentityOption);\n            command.Options.Add(ObsoleteTenantIdOption);\n            command.Options.Add(ObsoleteClientIdOption);\n            command.Options.Add(ObsoleteClientSecretOption);\n        }\n\n        internal DefaultAzureCredentialOptions CreateDefaultAzureCredentialOptions(ParseResult parseResult)\n        {\n            DefaultAzureCredentialOptions options = new();\n\n            string? managedIdentityClientId = parseResult.GetValue(ManagedIdentityClientIdOption);\n            if (managedIdentityClientId is not null)\n            {\n                options.ManagedIdentityClientId = managedIdentityClientId;\n            }\n\n            string? managedIdentityResourceId = parseResult.GetValue(ManagedIdentityResourceIdOption);\n            if (managedIdentityResourceId is not null)\n            {\n                options.ManagedIdentityResourceId = new ResourceIdentifier(managedIdentityResourceId);\n            }\n\n            return options;\n        }\n\n        internal TokenCredential? CreateTokenCredential(ParseResult parseResult)\n        {\n            bool? useManagedIdentity = parseResult.GetValue(ObsoleteManagedIdentityOption);\n\n            if (useManagedIdentity is not null)\n            {\n                Console.Out.WriteLine(Resources.ManagedIdentityOptionObsolete);\n            }\n\n            string? tenantId = parseResult.GetValue(ObsoleteTenantIdOption);\n            string? clientId = parseResult.GetValue(ObsoleteClientIdOption);\n            string? secret = parseResult.GetValue(ObsoleteClientSecretOption);\n\n            if (!string.IsNullOrEmpty(tenantId) &&\n                !string.IsNullOrEmpty(clientId) &&\n                !string.IsNullOrEmpty(secret))\n            {\n                Console.Out.WriteLine(Resources.ClientSecretOptionsObsolete);\n                return new ClientSecretCredential(tenantId, clientId, secret);\n            }\n\n            switch (parseResult.GetValue(CredentialTypeOption))\n            {\n                case AzureCredentialType.AzureCli:\n                    return new AzureCliCredential();\n\n                case AzureCredentialType.AzurePowerShell:\n                    return new AzurePowerShellCredential();\n\n                case AzureCredentialType.ManagedIdentity:\n                    string? managedIdentityClientId = parseResult.GetValue(ManagedIdentityClientIdOption);\n                    if (managedIdentityClientId is not null)\n                    {\n                        ManagedIdentityId managedIdentityId = ManagedIdentityId.FromUserAssignedClientId(managedIdentityClientId);\n\n                        return new ManagedIdentityCredential(managedIdentityId);\n                    }\n\n                    string? managedIdentityResourceId = parseResult.GetValue(ManagedIdentityResourceIdOption);\n                    if (managedIdentityResourceId is not null)\n                    {\n                        ResourceIdentifier resourceIdentifier = new(managedIdentityResourceId);\n                        ManagedIdentityId managedIdentityId = ManagedIdentityId.FromUserAssignedResourceId(resourceIdentifier);\n\n                        return new ManagedIdentityCredential(managedIdentityId);\n                    }\n\n                    return new ManagedIdentityCredential(ManagedIdentityId.SystemAssigned);\n\n                case AzureCredentialType.WorkloadIdentity:\n                    return new WorkloadIdentityCredential();\n\n                default:\n                    DefaultAzureCredentialOptions options = CreateDefaultAzureCredentialOptions(parseResult);\n\n                    // CodeQL [SM05137] Sign CLI is not a production service.\n                    return new DefaultAzureCredential(options);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/AzureCredentialType.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli\n{\n    internal static class AzureCredentialType\n    {\n        public const string AzureCli = \"azure-cli\";\n        public const string AzurePowerShell = \"azure-powershell\";\n        public const string ManagedIdentity = \"managed-identity\";\n        public const string WorkloadIdentity = \"workload-identity\";\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/AzureKeyVaultCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.CommandLine.Parsing;\nusing Azure.Core;\nusing Azure.Security.KeyVault.Certificates;\nusing Azure.Security.KeyVault.Keys.Cryptography;\nusing Microsoft.Extensions.Azure;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\nusing Sign.SignatureProviders.KeyVault;\n\nnamespace Sign.Cli\n{\n    internal sealed class AzureKeyVaultCommand : Command\n    {\n        internal Option<Uri> UrlOption { get; }\n        internal Option<string> CertificateOption { get; }\n        internal AzureCredentialOptions AzureCredentialOptions { get; } = new();\n\n        internal Argument<List<string>?> FilesArgument { get; }\n\n        internal AzureKeyVaultCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)\n            : base(\"azure-key-vault\", AzureKeyVaultResources.CommandDescription)\n        {\n            ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));\n            ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));\n\n            UrlOption = new Option<Uri>(\"--azure-key-vault-url\", \"-kvu\")\n            {\n                Description = AzureKeyVaultResources.UrlOptionDescription,\n                Required = true,\n                CustomParser = ParseUrl\n            };\n            CertificateOption = new Option<string>(\"--azure-key-vault-certificate\", \"-kvc\")\n            {\n                Description = AzureKeyVaultResources.CertificateOptionDescription,\n                Required = true\n            };\n            FilesArgument = new Argument<List<string>?>(\"file(s)\")\n            {\n                Description = Resources.FilesArgumentDescription,\n                Arity = ArgumentArity.OneOrMore\n            };\n\n            Options.Add(UrlOption);\n            Options.Add(CertificateOption);\n            AzureCredentialOptions.AddOptionsToCommand(this);\n\n            Arguments.Add(FilesArgument);\n\n            SetAction((ParseResult parseResult, CancellationToken cancellationToken) =>\n            {\n                List<string>? filesArgument = parseResult.GetValue(FilesArgument);\n\n                if (filesArgument is not { Count: > 0 })\n                {\n                    Console.Error.WriteLine(Resources.MissingFileValue);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                // this check exists as a courtesy to users who may have been signing .clickonce files via the old workaround.\n                // at some point we should remove this check, probably once we hit v1.0\n                if (filesArgument.Any(x => x.EndsWith(\".clickonce\", StringComparison.OrdinalIgnoreCase)))\n                {\n                    Console.Error.WriteLine(AzureKeyVaultResources.ClickOnceExtensionNotSupported);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                TokenCredential? credential = AzureCredentialOptions.CreateTokenCredential(parseResult);\n                if (credential is null)\n                {\n                    return Task.FromResult(ExitCode.Failed);\n                }\n\n                // Some of the options are required and that is why we can safely use\n                // the null-forgiving operator (!) to simplify the code.\n                Uri url = parseResult.GetValue(UrlOption)!;\n                string certificateId = parseResult.GetValue(CertificateOption)!;\n\n                // Construct the URI for the certificate and the key from user parameters. We'll validate those with the SDK\n                var certUri = new Uri($\"{url.Scheme}://{url.Authority}/certificates/{certificateId}\");\n\n                if (!KeyVaultCertificateIdentifier.TryCreate(certUri, out var certId))\n                {\n                    Console.Error.WriteLine(AzureKeyVaultResources.InvalidKeyVaultUrl);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                // The key uri is similar and the key name matches the certificate name\n                var keyUri = new Uri($\"{url.Scheme}://{url.Authority}/keys/{certificateId}\");\n\n                serviceProviderFactory.AddServices(services =>\n                {\n                    services.AddAzureClients(builder =>\n                    {\n                        builder.AddCertificateClient(certId.VaultUri);\n                        builder.AddCryptographyClient(keyUri);\n                        builder.UseCredential(credential);\n                        builder.ConfigureDefaults(options => options.Retry.Mode = RetryMode.Exponential);\n                    });\n\n                    services.AddSingleton<KeyVaultService>(serviceProvider =>\n                    {\n                        return new KeyVaultService(\n                            serviceProvider.GetRequiredService<CertificateClient>(),\n                            serviceProvider.GetRequiredService<CryptographyClient>(),\n                            certId.Name,\n                            serviceProvider.GetRequiredService<ILogger<KeyVaultService>>());\n                    });\n                });\n\n                KeyVaultServiceProvider keyVaultServiceProvider = new();\n\n                return codeCommand.HandleAsync(parseResult, serviceProviderFactory, keyVaultServiceProvider, filesArgument);\n            });\n        }\n\n        private static Uri? ParseUrl(ArgumentResult result)\n        {\n            if (result.Tokens.Count != 1 ||\n                !Uri.TryCreate(result.Tokens[0].Value, UriKind.Absolute, out Uri? uri)\n                || !string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))\n            {\n                result.AddError(AzureKeyVaultResources.InvalidUrlValue);\n\n                return null;\n            }\n\n            return uri;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/AzureKeyVaultResources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Cli {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"18.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class AzureKeyVaultResources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal AzureKeyVaultResources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Cli.AzureKeyVaultResources\", typeof(AzureKeyVaultResources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Name of the certificate in Azure Key Vault..\n        /// </summary>\n        internal static string CertificateOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation..\n        /// </summary>\n        internal static string ClickOnceExtensionNotSupported {\n            get {\n                return ResourceManager.GetString(\"ClickOnceExtensionNotSupported\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use Azure Key Vault..\n        /// </summary>\n        internal static string CommandDescription {\n            get {\n                return ResourceManager.GetString(\"CommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/).\n        /// </summary>\n        internal static string InvalidKeyVaultUrl {\n            get {\n                return ResourceManager.GetString(\"InvalidKeyVaultUrl\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to URL must be an absolute HTTPS URL to an Azure Key Vault..\n        /// </summary>\n        internal static string InvalidUrlValue {\n            get {\n                return ResourceManager.GetString(\"InvalidUrlValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to URL to an Azure Key Vault..\n        /// </summary>\n        internal static string UrlOptionDescription {\n            get {\n                return ResourceManager.GetString(\"UrlOptionDescription\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/AzureKeyVaultResources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"CertificateOptionDescription\" xml:space=\"preserve\">\n    <value>Name of the certificate in Azure Key Vault.</value>\n  </data>\n  <data name=\"ClickOnceExtensionNotSupported\" xml:space=\"preserve\">\n    <value>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</value>\n  </data>\n  <data name=\"CommandDescription\" xml:space=\"preserve\">\n    <value>Use Azure Key Vault.</value>\n  </data>\n  <data name=\"InvalidKeyVaultUrl\" xml:space=\"preserve\">\n    <value>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</value>\n  </data>\n  <data name=\"InvalidUrlValue\" xml:space=\"preserve\">\n    <value>URL must be an absolute HTTPS URL to an Azure Key Vault.</value>\n  </data>\n  <data name=\"UrlOptionDescription\" xml:space=\"preserve\">\n    <value>URL to an Azure Key Vault.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.Cli/CertificateStoreCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.CommandLine.Parsing;\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing Sign.Core;\nusing Sign.SignatureProviders.CertificateStore;\n\nnamespace Sign.Cli\n{\n    internal sealed class CertificateStoreCommand : Command\n    {\n        internal Option<string?> CertificateFingerprintOption { get; }\n        internal Option<string?> CertificateFileOption { get; }\n        internal Option<string?> CertificatePasswordOption { get; }\n        internal Option<string?> CryptoServiceProviderOption { get; }\n        internal Option<string?> PrivateKeyContainerOption { get; }\n        internal Option<bool> UseMachineKeyContainerOption { get; }\n        internal Option<bool> InteractiveOption { get; }\n\n        internal Argument<List<string>?> FilesArgument { get; }\n\n        internal CertificateStoreCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)\n            : base(\"certificate-store\", Resources.CertificateStoreCommandDescription)\n        {\n            ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));\n            ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));\n\n            CertificateFingerprintOption = new Option<string?>(\"--certificate-fingerprint\", \"-cfp\")\n            {\n                CustomParser = ParseCertificateFingerprint,\n                Description = CertificateStoreResources.CertificateFingerprintOptionDescription,\n                Required = true\n            };\n            CertificateFileOption = new Option<string?>(\"--certificate-file\", \"-cf\")\n            {\n                Description = CertificateStoreResources.CertificateFileOptionDescription\n            };\n            CertificatePasswordOption = new Option<string?>(\"--password\", \"-p\")\n            {\n                Description = CertificateStoreResources.CertificatePasswordOptionDescription\n            };\n            CryptoServiceProviderOption = new Option<string?>(\"--crypto-service-provider\", \"-csp\")\n            {\n                Description = CertificateStoreResources.CspOptionDescription\n            };\n            PrivateKeyContainerOption = new Option<string?>(\"--key-container\", \"-k\")\n            {\n                Description = CertificateStoreResources.KeyContainerOptionDescription\n            };\n            UseMachineKeyContainerOption = new Option<bool>(\"--use-machine-key-container\", \"-km\")\n            {\n                DefaultValueFactory = _ => false,\n                Description = CertificateStoreResources.UseMachineKeyContainerOptionDescription\n            };\n            InteractiveOption = new Option<bool>(\"--interactive\", \"-i\")\n            {\n                DefaultValueFactory = _ => false,\n                Description = CertificateStoreResources.InteractiveDescription\n            };\n            FilesArgument = new Argument<List<string>?>(\"file(s)\")\n            {\n                Description = Resources.FilesArgumentDescription,\n                Arity = ArgumentArity.OneOrMore\n            };\n\n            Options.Add(CertificateFingerprintOption);\n            Options.Add(CertificateFileOption);\n            Options.Add(CertificatePasswordOption);\n            Options.Add(CryptoServiceProviderOption);\n            Options.Add(PrivateKeyContainerOption);\n            Options.Add(UseMachineKeyContainerOption);\n            Options.Add(InteractiveOption);\n            Arguments.Add(FilesArgument);\n\n            SetAction((ParseResult parseResult, CancellationToken cancellationToken) =>\n            {\n                List<string>? filesArgument = parseResult.GetValue(FilesArgument);\n\n                if (filesArgument is not { Count: > 0 })\n                {\n                    Console.Error.WriteLine(Resources.MissingFileValue);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                // Some of the options are required and that is why we can safely use\n                // the null-forgiving operator (!) to simplify the code.\n                string certificateFingerprint = parseResult.GetValue(CertificateFingerprintOption)!;\n                string? certificatePath = parseResult.GetValue(CertificateFileOption);\n                string? certificatePassword = parseResult.GetValue(CertificatePasswordOption);\n                string? cryptoServiceProvider = parseResult.GetValue(CryptoServiceProviderOption);\n                string? privateKeyContainer = parseResult.GetValue(PrivateKeyContainerOption);\n                bool useMachineKeyContainer = parseResult.GetValue(UseMachineKeyContainerOption);\n                bool isInteractive = parseResult.GetValue(InteractiveOption);\n\n                // Certificate fingerprint is required in case the provided certificate container contains multiple certificates.\n                if (string.IsNullOrEmpty(certificateFingerprint))\n                {\n                    Console.Error.WriteFormattedLine(\n                        Resources.InvalidCertificateFingerprintValue,\n                        CertificateFingerprintOption);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                if (!TryDeduceHashAlgorithm(certificateFingerprint, out HashAlgorithmName certificateFingerprintAlgorithm))\n                {\n                    Console.Error.WriteFormattedLine(\n                        Resources.InvalidCertificateFingerprintValue,\n                        CertificateFingerprintOption);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                // CSP requires a private key container to function.\n                if (string.IsNullOrEmpty(cryptoServiceProvider) != string.IsNullOrEmpty(privateKeyContainer))\n                {\n                    if (string.IsNullOrEmpty(privateKeyContainer))\n                    {\n                        Console.Error.WriteLine(CertificateStoreResources.MissingPrivateKeyContainerError);\n\n                        return Task.FromResult(ExitCode.InvalidOptions);\n                    }\n                    else\n                    {\n                        Console.Error.WriteLine(CertificateStoreResources.MissingCspError);\n\n                        return Task.FromResult(ExitCode.InvalidOptions);\n                    }\n                }\n\n                CertificateStoreServiceProvider certificateStoreServiceProvider = new(\n                    certificateFingerprint,\n                    certificateFingerprintAlgorithm,\n                    cryptoServiceProvider,\n                    privateKeyContainer,\n                    certificatePath,\n                    certificatePassword,\n                    useMachineKeyContainer,\n                    isInteractive);\n\n                return codeCommand.HandleAsync(parseResult, serviceProviderFactory, certificateStoreServiceProvider, filesArgument);\n            });\n        }\n\n        private static string? ParseCertificateFingerprint(ArgumentResult result)\n        {\n            string? token = null;\n\n            if (result.Tokens.Count == 1)\n            {\n                token = result.Tokens[0].Value;\n\n                if (!HexHelpers.IsHex(token))\n                {\n                    result.AddError(FormatMessage(\n                        Resources.InvalidCertificateFingerprintValue,\n                        result.Argument));\n                }\n                else if (!TryDeduceHashAlgorithm(token, out HashAlgorithmName hashAlgorithmName))\n                {\n                    result.AddError(FormatMessage(\n                        Resources.InvalidCertificateFingerprintValue,\n                        result.Argument));\n                }\n            }\n            else\n            {\n                result.AddError(FormatMessage(\n                    Resources.InvalidCertificateFingerprintValue,\n                    result.Argument));\n            }\n\n            return token;\n        }\n\n        private static string FormatMessage(string format, Argument argument)\n        {\n            return string.Format(CultureInfo.CurrentCulture, format, argument.Name);\n        }\n\n        private static bool TryDeduceHashAlgorithm(\n            string certificateFingerprint,\n            out HashAlgorithmName hashAlgorithmName)\n        {\n            hashAlgorithmName = HashAlgorithmName.SHA256;\n\n            if (string.IsNullOrEmpty(certificateFingerprint))\n            {\n                return false;\n            }\n\n            // One hexadecimal character is 4 bits.\n            switch (certificateFingerprint.Length)\n            {\n                case 64: // 64 characters * 4 bits/character = 256 bits\n                    hashAlgorithmName = HashAlgorithmName.SHA256;\n                    return true;\n\n                case 96: // 96 characters * 4 bits/character = 384 bits\n                    hashAlgorithmName = HashAlgorithmName.SHA384;\n                    return true;\n\n                case 128: // 128 characters * 4 bits/character = 512 bits\n                    hashAlgorithmName = HashAlgorithmName.SHA512;\n                    return true;\n\n                default:\n                    return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/CertificateStoreResources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Cli {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class CertificateStoreResources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal CertificateStoreResources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Cli.CertificateStoreResources\", typeof(CertificateStoreResources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to PFX, P7B, or CER file containing a certificate and potentially a private key..\n        /// </summary>\n        internal static string CertificateFileOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateFileOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to SHA fingerprint used to identify a certificate..\n        /// </summary>\n        internal static string CertificateFingerprintOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateFingerprintOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Password for certificate file..\n        /// </summary>\n        internal static string CertificatePasswordOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificatePasswordOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Sign container contents.\n        /// </summary>\n        internal static string ContainersDescription {\n            get {\n                return ResourceManager.GetString(\"ContainersDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Cryptographic Service Provider containing the private key container. Requires /k and optionally /km..\n        /// </summary>\n        internal static string CspOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CspOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Allow user interactions (such as a dialog box) when a private key is accessed..\n        /// </summary>\n        internal static string InteractiveDescription {\n            get {\n                return ResourceManager.GetString(\"InteractiveDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Private key container name..\n        /// </summary>\n        internal static string KeyContainerOptionDescription {\n            get {\n                return ResourceManager.GetString(\"KeyContainerOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Cryptographic Service Provider missing.  Use /csp to specify a CSP..\n        /// </summary>\n        internal static string MissingCspError {\n            get {\n                return ResourceManager.GetString(\"MissingCspError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Private key container name missing. Use /k to specify a key container name..\n        /// </summary>\n        internal static string MissingPrivateKeyContainerError {\n            get {\n                return ResourceManager.GetString(\"MissingPrivateKeyContainerError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use a machine-level private key container.  (The default is user-level.).\n        /// </summary>\n        internal static string UseMachineKeyContainerOptionDescription {\n            get {\n                return ResourceManager.GetString(\"UseMachineKeyContainerOptionDescription\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/CertificateStoreResources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"InteractiveDescription\" xml:space=\"preserve\">\n    <value>Allow user interactions (such as a dialog box) when a private key is accessed.</value>\n  </data>\n  <data name=\"CertificateFileOptionDescription\" xml:space=\"preserve\">\n    <value>PFX, P7B, or CER file containing a certificate and potentially a private key.</value>\n    <comment>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</comment>\n  </data>\n  <data name=\"CertificateFingerprintOptionDescription\" xml:space=\"preserve\">\n    <value>SHA fingerprint used to identify a certificate.</value>\n    <comment>{Locked=\"SHA\"} is a cryptographic algorithm.</comment>\n  </data>\n  <data name=\"CertificatePasswordOptionDescription\" xml:space=\"preserve\">\n    <value>Password for certificate file.</value>\n  </data>\n  <data name=\"CspOptionDescription\" xml:space=\"preserve\">\n    <value>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</value>\n    <comment>{Locked=\"/k\", \"/km\"} are command line options.</comment>\n  </data>\n  <data name=\"KeyContainerOptionDescription\" xml:space=\"preserve\">\n    <value>Private key container name.</value>\n  </data>\n  <data name=\"MissingCspError\" xml:space=\"preserve\">\n    <value>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</value>\n    <comment>{Locked=\"/csp\"} is a command line option.</comment>\n  </data>\n  <data name=\"MissingPrivateKeyContainerError\" xml:space=\"preserve\">\n    <value>Private key container name missing. Use /k to specify a key container name.</value>\n    <comment>{Locked=\"/k\"} is a command line option.</comment>\n  </data>\n  <data name=\"UseMachineKeyContainerOptionDescription\" xml:space=\"preserve\">\n    <value>Use a machine-level private key container.  (The default is user-level.)</value>\n  </data>\n  <data name=\"ContainersDescription\" xml:space=\"preserve\">\n    <value>Sign container contents.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.Cli/CodeCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.CommandLine.Parsing;\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing System.Text;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\n\nnamespace Sign.Cli\n{\n    internal sealed class CodeCommand : Command\n    {\n        internal Option<string?> ApplicationNameOption { get; }\n        internal Option<DirectoryInfo> BaseDirectoryOption { get; }\n        internal Option<string> DescriptionOption { get; }\n        internal Option<Uri?> DescriptionUrlOption { get; }\n        internal Option<HashAlgorithmName> FileDigestOption { get; }\n        internal Option<string?> FileListOption { get; }\n        internal Option<bool> RecurseContainersOption { get; }\n        internal Option<int> MaxConcurrencyOption { get; }\n        internal Option<string?> OutputOption { get; }\n        internal Option<string?> PublisherNameOption { get; }\n        internal Option<HashAlgorithmName> TimestampDigestOption { get; }\n        internal Option<Uri?> TimestampUrlOption { get; }\n        internal Option<LogLevel> VerbosityOption { get; }\n\n        internal CodeCommand()\n            : base(\"code\", Resources.CodeCommandDescription)\n        {\n            ApplicationNameOption = new Option<string?>(\"--application-name\", \"-an\")\n            {\n                Description = Resources.ApplicationNameOptionDescription,\n                Recursive = true\n            };\n            BaseDirectoryOption = new Option<DirectoryInfo>(\"--base-directory\", \"-b\")\n            {\n                CustomParser = ParseBaseDirectoryOption,\n                DefaultValueFactory = _ => new DirectoryInfo(Environment.CurrentDirectory),\n                Description = Resources.BaseDirectoryOptionDescription,\n                Recursive = true\n            };\n            DescriptionOption = new Option<string>(\"--description\", \"-d\")\n            {\n                Description = Resources.DescriptionOptionDescription,\n                Recursive = true\n            };\n            DescriptionUrlOption = new Option<Uri?>(\"--description-url\", \"-u\")\n            {\n                CustomParser = ParseUrl,\n                Description = Resources.DescriptionUrlOptionDescription,\n                Recursive = true\n            };\n            FileDigestOption = new Option<HashAlgorithmName>(\"--file-digest\", \"-fd\")\n            {\n                CustomParser = HashAlgorithmParser.ParseHashAlgorithmName,\n                DefaultValueFactory = _ => HashAlgorithmName.SHA256,\n                Description = Resources.FileDigestOptionDescription,\n                Recursive = true\n            };\n            FileListOption = new Option<string?>(\"--file-list\", \"-fl\")\n            {\n                Description = Resources.FileListOptionDescription,\n                Recursive = true\n            };\n            RecurseContainersOption = new Option<bool>(\"--recurse-containers\", \"-rc\")\n            {\n                DefaultValueFactory = _ => true,\n                Description = CertificateStoreResources.ContainersDescription,\n                Recursive = true\n            };\n            MaxConcurrencyOption = new Option<int>(\"--max-concurrency\", \"-m\")\n            {\n                CustomParser = ParseMaxConcurrencyOption,\n                DefaultValueFactory = _ => 4,\n                Description = Resources.MaxConcurrencyOptionDescription,\n                Recursive = true\n            };\n            OutputOption = new Option<string?>(\"--output\", \"-o\")\n            {\n                Description = Resources.OutputOptionDescription,\n                Recursive = true\n            };\n            PublisherNameOption = new Option<string?>(\"--publisher-name\", \"-pn\")\n            {\n                Description = Resources.PublisherNameOptionDescription,\n                Recursive = true\n            };\n            TimestampDigestOption = new Option<HashAlgorithmName>(\"--timestamp-digest\", \"-td\")\n            {\n                CustomParser = HashAlgorithmParser.ParseHashAlgorithmName,\n                DefaultValueFactory = _ => HashAlgorithmName.SHA256,\n                Description = Resources.TimestampDigestOptionDescription,\n                Recursive = true\n            };\n            TimestampUrlOption = new Option<Uri?>(\"--timestamp-url\", \"-t\")\n            {\n                CustomParser = ParseUrl,\n                DefaultValueFactory = _ => new Uri(\"http://timestamp.acs.microsoft.com\"),\n                Description = Resources.TimestampUrlOptionDescription,\n                Recursive = true\n            };\n            VerbosityOption = new Option<LogLevel>(\"--verbosity\", \"-v\")\n            {\n                Description = Resources.VerbosityOptionDescription,\n                Recursive = true\n            };\n\n            // These options are available on the adding command and all subcommands.\n            // Order here is significant as it represents the order in which options are\n            // displayed in help.\n            Options.Add(ApplicationNameOption);\n            Options.Add(DescriptionOption);\n            Options.Add(DescriptionUrlOption);\n            Options.Add(BaseDirectoryOption);\n            Options.Add(OutputOption);\n            Options.Add(PublisherNameOption);\n            Options.Add(FileListOption);\n            Options.Add(RecurseContainersOption);\n            Options.Add(FileDigestOption);\n            Options.Add(TimestampUrlOption);\n            Options.Add(TimestampDigestOption);\n            Options.Add(MaxConcurrencyOption);\n            Options.Add(VerbosityOption);\n        }\n\n        internal async Task<int> HandleAsync(ParseResult parseResult, IServiceProviderFactory serviceProviderFactory, ISignatureProvider signatureProvider, IEnumerable<string> filesArgument)\n        {\n            // Some of the options have a default value and that is why we can safely use\n            // the null-forgiving operator (!) to simplify the code.\n            DirectoryInfo baseDirectory = parseResult.GetValue(BaseDirectoryOption)!;\n            string? applicationName = parseResult.GetValue(ApplicationNameOption);\n            string? publisherName = parseResult.GetValue(PublisherNameOption);\n            string? description = parseResult.GetValue(DescriptionOption);\n            Uri? descriptionUrl = parseResult.GetValue(DescriptionUrlOption);\n            string? fileListFilePath = parseResult.GetValue(FileListOption);\n            bool recurseContainers = parseResult.GetValue(RecurseContainersOption);\n            HashAlgorithmName fileHashAlgorithmName = parseResult.GetValue(FileDigestOption);\n            HashAlgorithmName timestampHashAlgorithmName = parseResult.GetValue(TimestampDigestOption);\n            Uri timestampUrl = parseResult.GetValue(TimestampUrlOption)!;\n            LogLevel verbosity = parseResult.GetValue(VerbosityOption);\n            string? output = parseResult.GetValue(OutputOption);\n            int maxConcurrency = parseResult.GetValue(MaxConcurrencyOption);\n\n            // Make sure this is rooted\n            if (!Path.IsPathRooted(baseDirectory.FullName))\n            {\n                Console.Error.WriteFormattedLine(\n                    Resources.InvalidBaseDirectoryValue,\n                    BaseDirectoryOption);\n\n                return ExitCode.InvalidOptions;\n            }\n\n            IServiceProvider serviceProvider = serviceProviderFactory.Create(\n                verbosity,\n                addServices: (IServiceCollection services) =>\n                {\n                    services.AddSingleton<ISignatureAlgorithmProvider>(\n                        (IServiceProvider serviceProvider) => signatureProvider.GetSignatureAlgorithmProvider(serviceProvider));\n                    services.AddSingleton<ICertificateProvider>(\n                        (IServiceProvider serviceProvider) => signatureProvider.GetCertificateProvider(serviceProvider));\n                });\n\n            List<FileInfo> inputFiles = [];\n\n            foreach (string fileArgument in filesArgument)\n            {\n                // If we're going to glob, we can't be fully rooted currently (fix me later)\n                bool isGlob = fileArgument.Contains('*');\n\n                if (isGlob)\n                {\n                    if (Path.IsPathRooted(fileArgument))\n                    {\n                        Console.Error.WriteLine(Resources.InvalidFileValue);\n                        return ExitCode.InvalidOptions;\n                    }\n\n                    IFileListReader fileListReader = serviceProvider.GetRequiredService<IFileListReader>();\n                    IFileMatcher fileMatcher = serviceProvider.GetRequiredService<IFileMatcher>();\n\n                    using (MemoryStream stream = new(Encoding.UTF8.GetBytes(fileArgument)))\n                    using (StreamReader reader = new(stream))\n                    {\n                        fileListReader.Read(reader, out Matcher? matcher, out Matcher? antiMatcher);\n\n                        DirectoryInfoBase directory = new DirectoryInfoWrapper(baseDirectory);\n\n                        IEnumerable<FileInfo> matches = fileMatcher.EnumerateMatches(directory, matcher);\n\n                        if (antiMatcher is not null)\n                        {\n                            IEnumerable<FileInfo> antiMatches = fileMatcher.EnumerateMatches(directory, antiMatcher);\n                            matches = matches.Except(antiMatches, FileInfoComparer.Instance);\n                        }\n\n                        inputFiles.AddRange(matches);\n                    }\n                }\n                else\n                {\n                    inputFiles.Add(new FileInfo(ExpandFilePath(baseDirectory, fileArgument)));\n                }\n            }\n\n            FileInfo? fileList = null;\n            if (!string.IsNullOrEmpty(fileListFilePath))\n            {\n                if (Path.IsPathRooted(fileListFilePath))\n                {\n                    fileList = new FileInfo(fileListFilePath);\n                }\n                else\n                {\n                    fileList = new FileInfo(ExpandFilePath(baseDirectory, fileListFilePath));\n                }\n            }\n\n            if (inputFiles.Count == 0)\n            {\n                Console.Error.WriteLine(Resources.NoFilesToSign);\n\n                return ExitCode.NoInputsFound;\n            }\n\n            if (inputFiles.Any(file => !file.Exists))\n            {\n                Console.Error.WriteFormattedLine(\n                    Resources.SomeFilesDoNotExist,\n                    BaseDirectoryOption);\n\n                foreach (FileInfo file in inputFiles.Where(file => !file.Exists))\n                {\n                    Console.Error.WriteLine($\"    {file.FullName}\");\n                }\n\n                return ExitCode.NoInputsFound;\n            }\n\n            ISigner signer = serviceProvider.GetRequiredService<ISigner>();\n\n            int exitCode = await signer.SignAsync(\n                inputFiles,\n                output,\n                fileList,\n                recurseContainers,\n                baseDirectory,\n                applicationName,\n                publisherName,\n                description,\n                descriptionUrl,\n                timestampUrl,\n                maxConcurrency,\n                fileHashAlgorithmName,\n                timestampHashAlgorithmName);\n\n            return exitCode;\n        }\n\n        private static string ExpandFilePath(DirectoryInfo baseDirectory, string file)\n        {\n            if (Path.IsPathRooted(file))\n            {\n                return file;\n            }\n\n            return Path.Combine(baseDirectory.FullName, file);\n        }\n\n        private static DirectoryInfo ParseBaseDirectoryOption(ArgumentResult result)\n        {\n            if (result.Tokens.Count != 1 ||\n                string.IsNullOrWhiteSpace(result.Tokens[0].Value))\n            {\n                result.AddError(FormatMessage(Resources.InvalidBaseDirectoryValue, result.Argument));\n\n                return new DirectoryInfo(Environment.CurrentDirectory);\n            }\n\n            string value = result.Tokens[0].Value;\n\n            if (Path.IsPathRooted(value))\n            {\n                return new DirectoryInfo(value);\n            }\n\n            result.AddError(FormatMessage(Resources.InvalidBaseDirectoryValue, result.Argument));\n\n            return new DirectoryInfo(Environment.CurrentDirectory);\n        }\n\n        private static int ParseMaxConcurrencyOption(ArgumentResult result)\n        {\n            if (result.Tokens.Count != 1 ||\n                !int.TryParse(result.Tokens[0].Value, out int value) ||\n                value < 1)\n            {\n                result.AddError(FormatMessage(Resources.InvalidMaxConcurrencyValue, result.Argument));\n\n                return default;\n            }\n\n            return value;\n        }\n\n        internal static Uri? ParseHttpsUrl(ArgumentResult result)\n        {\n            if (result.Tokens.Count != 1 ||\n                !Uri.TryCreate(result.Tokens[0].Value, UriKind.Absolute, out Uri? uri) ||\n                !string.Equals(Uri.UriSchemeHttps, uri.Scheme, StringComparison.OrdinalIgnoreCase))\n            {\n                result.AddError(FormatMessage(Resources.InvalidHttpsUrlValue, result.Argument));\n\n                return null;\n            }\n\n            return uri;\n        }\n\n        internal static Uri? ParseUrl(ArgumentResult result)\n        {\n            if (result.Tokens.Count != 1 ||\n                !Uri.TryCreate(result.Tokens[0].Value, UriKind.Absolute, out Uri? uri) ||\n                !(string.Equals(Uri.UriSchemeHttp, uri.Scheme, StringComparison.OrdinalIgnoreCase) ||\n                    string.Equals(Uri.UriSchemeHttps, uri.Scheme, StringComparison.OrdinalIgnoreCase)))\n            {\n                result.AddError(FormatMessage(Resources.InvalidUrlValue, result.Argument));\n\n                return null;\n            }\n\n            return uri;\n        }\n\n        private static string FormatMessage(string format, Argument argument)\n        {\n            return string.Format(CultureInfo.CurrentCulture, format, argument.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/Helpers/HashAlgorithmParser.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine.Parsing;\nusing System.Globalization;\nusing System.Security.Cryptography;\n\nnamespace Sign.Cli\n{\n    internal static class HashAlgorithmParser\n    {\n        public static HashAlgorithmName ParseHashAlgorithmName(ArgumentResult result)\n        {\n            if (result.Tokens.Count == 0)\n            {\n                return HashAlgorithmName.SHA256;\n            }\n\n            string token = result.Tokens.Single().Value.ToLowerInvariant();\n\n            switch (token)\n            {\n                case \"sha256\":\n                    return HashAlgorithmName.SHA256;\n\n                case \"sha384\":\n                    return HashAlgorithmName.SHA384;\n\n                case \"sha512\":\n                    return HashAlgorithmName.SHA512;\n\n                default:\n                    result.AddError(string.Format(CultureInfo.CurrentCulture, Resources.InvalidDigestValue, result.Argument.Name));\n\n                    return HashAlgorithmName.SHA256;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/Kernel32.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.ComponentModel;\nusing System.Runtime.InteropServices;\n\nnamespace Sign.Cli\n{\n#pragma warning disable IDE1006 // Naming Styles\n    static class Kernel32\n    {\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool SetDllDirectoryW(\n            [MarshalAs(UnmanagedType.LPWStr)] string lpPathName);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        public static extern IntPtr LoadLibraryW(\n            [MarshalAs(UnmanagedType.LPWStr)] string path);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        public static extern IntPtr CreateActCtxW(ref ACTCTX pActCtx);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool DeactivateActCtx(int dwFlags, IntPtr lpCookie);\n\n        [DllImport(\"kernel32.dll\", PreserveSig = true)]\n        public static extern void ReleaseActCtx(IntPtr hActCtx);\n\n        [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]\n        public struct ACTCTX\n        {\n            public int cbSize;\n            public ActivationContextFlags dwFlags;\n            public string lpSource;\n            public ushort wProcessorArchitecture;\n            public ushort wLangId;\n            public string lpAssemblyDirectory;\n            public string lpResourceName;\n            public string lpApplicationName;\n            public IntPtr hModule;\n        }\n\n        [Flags]\n        public enum ActivationContextFlags : uint\n        {\n            ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x008,\n            ACTCTX_FLAG_APPLICATION_NAME_VALID = 0x020\n        }\n\n        public sealed class ActivationContext : IDisposable\n        {\n            readonly IntPtr INVALID_HANDLE_VALUE = new(-1);\n            IntPtr activationContext = new(-1);\n            IntPtr activationContextCookie;\n\n            public ActivationContext(string assemblyName)\n            {\n                var requestedActivationContext = new ACTCTX\n                {\n                    cbSize = Marshal.SizeOf<ACTCTX>(),\n                    lpSource = assemblyName\n                };\n\n                activationContext = CreateActCtxW(ref requestedActivationContext);\n                if (activationContext != INVALID_HANDLE_VALUE)\n                {\n                    if (!ActivateActCtx(activationContext, out activationContextCookie))\n                    {\n                        throw new Win32Exception(Marshal.GetLastWin32Error());\n                    }\n                }\n                else\n                {\n                    throw new Win32Exception(Marshal.GetLastWin32Error());\n                }\n            }\n\n            public void Dispose()\n            {\n                if (activationContextCookie != IntPtr.Zero)\n                {\n                    if (!DeactivateActCtx(dwFlags: 0, activationContextCookie))\n                    {\n                        throw new Win32Exception(Marshal.GetLastWin32Error());\n                    }\n\n                    activationContextCookie = IntPtr.Zero;\n                }\n\n                if (activationContext != INVALID_HANDLE_VALUE)\n                {\n                    ReleaseActCtx(activationContext);\n                    activationContext = INVALID_HANDLE_VALUE;\n                }\n            }\n        }\n    }\n#pragma warning restore IDE1006 // Naming Styles\n}"
  },
  {
    "path": "src/Sign.Cli/PACKAGE.md",
    "content": "## About\n\nSign CLI is a .NET tool that provides digital signing for .NET assemblies, packages, and other files.\n\nThe tool signs files inside-out, starting with the most nested files and then the outer files, ensuring everything is signed in the correct order.\n\n## Prerequisites\n\n- An up-to-date x64-based version of Windows currently in [mainstream support](https://learn.microsoft.com/lifecycle/products/)\n- [.NET 8 SDK or later](https://dotnet.microsoft.com/download)\n- [Microsoft Visual C++ 14 runtime](https://aka.ms/vs/17/release/vc_redist.x64.exe)\n- For ClickOnce and VSTO signing:  A recent --- ideally, the latest --- version of [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework)\n\n## Usage\n\n- For help with...\n    - Azure Key Vault:  `sign code azure-key-vault --help`\n    - Artifact Signing:  `sign code artifact-signing --help`\n    - local signing:  `sign code certificate-store --help`\n- Version information:  `sign --version`\n\nSee the [GitHub repository](https://github.com/dotnet/sign) for additional information and samples.\n\n## License\n\nThis package is released as open source under the [MIT license](https://licenses.nuget.org/MIT).\n\n## Feedback\n\nBug reports, feedback, and contributions are welcome at the [GitHub repository](https://github.com/dotnet/sign).\n\nHappy signing! 🚀\n"
  },
  {
    "path": "src/Sign.Cli/Program.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Sign.Core;\n\nnamespace Sign.Cli\n{\n    internal static class Program\n    {\n        internal static async Task<int> Main(string[] args)\n        {\n            using (new TemporaryConsoleEncoding())\n            {\n                if (!Environment.Is64BitProcess)\n                {\n                    Console.Error.WriteLine(Resources.x86NotSupported);\n\n                    return ExitCode.Failed;\n                }\n\n                AppInitializer.Initialize();\n\n                string systemDirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.System);\n\n                // NavSip.dll has a dependency on this.\n                string vcRuntime140FilePath = Path.Combine(systemDirectoryPath, \"vcruntime140.dll\");\n\n                if (!File.Exists(vcRuntime140FilePath))\n                {\n                    WriteWarning(Resources.MsvcrtNotDetected);\n                }\n\n                try\n                {\n                    SignCommand rootCommand = CreateCommand(serviceProviderFactory: null);\n\n                    return await rootCommand.Parse(args).InvokeAsync();\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine(ex);\n\n                    return ExitCode.Failed;\n                }\n            }\n        }\n\n        private static void WriteWarning(string warning)\n        {\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(warning);\n            Console.ResetColor();\n        }\n\n        internal static SignCommand CreateCommand(IServiceProviderFactory? serviceProviderFactory = null)\n        {\n            return new SignCommand(serviceProviderFactory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Sign.Cli\": {\n      \"commandName\": \"Project\",\n      \"commandLineArgs\": \"code certificate-store -b C:\\\\Trash -v trace -cf C:\\\\git\\\\Entropy\\\\MakeTestCert\\\\af994810f3d0d01b5f6f37e8be085e1a537d40c9.pfx -cfp 0695cf4875ae67f2194ea4c2cbcdcb1327c6874d5949321c4d8028bed308b7a6 MakeTestCert.dll -o MakeTestCert.signed.dll\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/Sign.Cli/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Cli {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Cli.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Application name (ClickOnce)..\n        /// </summary>\n        internal static string ApplicationNameOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ApplicationNameOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Base directory for files.  Overrides the current working directory..\n        /// </summary>\n        internal static string BaseDirectoryOptionDescription {\n            get {\n                return ResourceManager.GetString(\"BaseDirectoryOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use Windows Certificate Store or a local certificate file..\n        /// </summary>\n        internal static string CertificateStoreCommandDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateStoreCommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Client ID to authenticate to Azure..\n        /// </summary>\n        internal static string ClientIdOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ClientIdOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Client secret to authenticate to Azure..\n        /// </summary>\n        internal static string ClientSecretOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ClientSecretOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The client secret options are obsolete and should no longer be specified..\n        /// </summary>\n        internal static string ClientSecretOptionsObsolete {\n            get {\n                return ResourceManager.GetString(\"ClientSecretOptionsObsolete\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Sign binaries and containers..\n        /// </summary>\n        internal static string CodeCommandDescription {\n            get {\n                return ResourceManager.GetString(\"CodeCommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Azure credential type that will be used. This defaults to DefaultAzureCredential..\n        /// </summary>\n        internal static string CredentialTypeOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CredentialTypeOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Description of the signing certificate..\n        /// </summary>\n        internal static string DescriptionOptionDescription {\n            get {\n                return ResourceManager.GetString(\"DescriptionOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Description URL of the signing certificate..\n        /// </summary>\n        internal static string DescriptionUrlOptionDescription {\n            get {\n                return ResourceManager.GetString(\"DescriptionUrlOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Digest algorithm to hash files with. Allowed values are &apos;sha256&apos;, &apos;sha384&apos;, and &apos;sha512&apos;..\n        /// </summary>\n        internal static string FileDigestOptionDescription {\n            get {\n                return ResourceManager.GetString(\"FileDigestOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Path to file containing paths of files to sign or to exclude from signing..\n        /// </summary>\n        internal static string FileListOptionDescription {\n            get {\n                return ResourceManager.GetString(\"FileListOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to File(s) to sign..\n        /// </summary>\n        internal static string FilesArgumentDescription {\n            get {\n                return ResourceManager.GetString(\"FilesArgumentDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be a fully rooted directory path..\n        /// </summary>\n        internal static string InvalidBaseDirectoryValue {\n            get {\n                return ResourceManager.GetString(\"InvalidBaseDirectoryValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal)..\n        /// </summary>\n        internal static string InvalidCertificateFingerprintValue {\n            get {\n                return ResourceManager.GetString(\"InvalidCertificateFingerprintValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be &apos;sha256&apos;, &apos;sha384&apos;, or &apos;sha512&apos;..\n        /// </summary>\n        internal static string InvalidDigestValue {\n            get {\n                return ResourceManager.GetString(\"InvalidDigestValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used)..\n        /// </summary>\n        internal static string InvalidFileValue {\n            get {\n                return ResourceManager.GetString(\"InvalidFileValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be a number value greater than or equal to 1..\n        /// </summary>\n        internal static string InvalidMaxConcurrencyValue {\n            get {\n                return ResourceManager.GetString(\"InvalidMaxConcurrencyValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be an absolute HTTPS URL..\n        /// </summary>\n        internal static string InvalidHttpsUrlValue {\n            get {\n                return ResourceManager.GetString(\"InvalidHttpsUrlValue\", resourceCulture);\n            }\n        }\n\n        /// <summary>\n        ///   Looks up a localized string similar to Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL..\n        /// </summary>\n        internal static string InvalidUrlValue {\n            get {\n                return ResourceManager.GetString(\"InvalidUrlValue\", resourceCulture);\n            }\n        }\n\n        /// <summary>\n        ///   Looks up a localized string similar to The client id of a user assigned ManagedIdentity..\n        /// </summary>\n        internal static string ManagedIdentityClientIdOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ManagedIdentityClientIdOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Managed identity to authenticate to Azure Key. (obsolete).\n        /// </summary>\n        internal static string ManagedIdentityOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ManagedIdentityOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified..\n        /// </summary>\n        internal static string ManagedIdentityOptionObsolete {\n            get {\n                return ResourceManager.GetString(\"ManagedIdentityOptionObsolete\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The resource id of a user assigned ManagedIdentity..\n        /// </summary>\n        internal static string ManagedIdentityResourceIdOptionDescription {\n            get {\n                return ResourceManager.GetString(\"ManagedIdentityResourceIdOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Maximum concurrency..\n        /// </summary>\n        internal static string MaxConcurrencyOptionDescription {\n            get {\n                return ResourceManager.GetString(\"MaxConcurrencyOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to A file or glob is required..\n        /// </summary>\n        internal static string MissingFileValue {\n            get {\n                return ResourceManager.GetString(\"MissingFileValue\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe.\n        /// </summary>\n        internal static string MsvcrtNotDetected {\n            get {\n                return ResourceManager.GetString(\"MsvcrtNotDetected\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to No inputs found to sign..\n        /// </summary>\n        internal static string NoFilesToSign {\n            get {\n                return ResourceManager.GetString(\"NoFilesToSign\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Output file or directory. If omitted, input files will be overwritten..\n        /// </summary>\n        internal static string OutputOptionDescription {\n            get {\n                return ResourceManager.GetString(\"OutputOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Publisher name (ClickOnce)..\n        /// </summary>\n        internal static string PublisherNameOptionDescription {\n            get {\n                return ResourceManager.GetString(\"PublisherNameOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Sign CLI.\n        /// </summary>\n        internal static string SignCommandDescription {\n            get {\n                return ResourceManager.GetString(\"SignCommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Some files do not exist.  Try using a different {0} value or a fully qualified file path..\n        /// </summary>\n        internal static string SomeFilesDoNotExist {\n            get {\n                return ResourceManager.GetString(\"SomeFilesDoNotExist\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Tenant ID to authenticate to Azure..\n        /// </summary>\n        internal static string TenantIdOptionDescription {\n            get {\n                return ResourceManager.GetString(\"TenantIdOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512..\n        /// </summary>\n        internal static string TimestampDigestOptionDescription {\n            get {\n                return ResourceManager.GetString(\"TimestampDigestOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to RFC 3161 timestamp server URL..\n        /// </summary>\n        internal static string TimestampUrlOptionDescription {\n            get {\n                return ResourceManager.GetString(\"TimestampUrlOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Sets the verbosity level. Allowed values are &apos;none&apos;, &apos;critical&apos;, &apos;error&apos;, &apos;warning&apos;, &apos;information&apos;, &apos;debug&apos;, and &apos;trace&apos;..\n        /// </summary>\n        internal static string VerbosityOptionDescription {\n            get {\n                return ResourceManager.GetString(\"VerbosityOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The trusted-signing command is obsolete. Use the artifact-signing command instead..\n        /// </summary>\n        internal static string TrustedSigningCommandObsolete {\n            get {\n                return ResourceManager.GetString(\"TrustedSigningCommandObsolete\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support..\n        /// </summary>\n        internal static string x86NotSupported {\n            get {\n                return ResourceManager.GetString(\"x86NotSupported\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"ApplicationNameOptionDescription\" xml:space=\"preserve\">\n    <value>Application name (ClickOnce).</value>\n  </data>\n  <data name=\"BaseDirectoryOptionDescription\" xml:space=\"preserve\">\n    <value>Base directory for files.  Overrides the current working directory.</value>\n  </data>\n  <data name=\"CertificateStoreCommandDescription\" xml:space=\"preserve\">\n    <value>Use Windows Certificate Store or a local certificate file.</value>\n  </data>\n  <data name=\"ClientIdOptionDescription\" xml:space=\"preserve\">\n    <value>Client ID to authenticate to Azure.</value>\n  </data>\n  <data name=\"ClientSecretOptionDescription\" xml:space=\"preserve\">\n    <value>Client secret to authenticate to Azure.</value>\n  </data>\n  <data name=\"ClientSecretOptionsObsolete\" xml:space=\"preserve\">\n    <value>The client secret options are obsolete and should no longer be specified.</value>\n  </data>\n  <data name=\"CodeCommandDescription\" xml:space=\"preserve\">\n    <value>Sign binaries and containers.</value>\n  </data>\n  <data name=\"DescriptionOptionDescription\" xml:space=\"preserve\">\n    <value>Description of the signing certificate.</value>\n  </data>\n  <data name=\"DescriptionUrlOptionDescription\" xml:space=\"preserve\">\n    <value>Description URL of the signing certificate.</value>\n  </data>\n  <data name=\"FileDigestOptionDescription\" xml:space=\"preserve\">\n    <value>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</value>\n    <comment>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</comment>\n  </data>\n  <data name=\"FileListOptionDescription\" xml:space=\"preserve\">\n    <value>Path to file containing paths of files to sign or to exclude from signing.</value>\n  </data>\n  <data name=\"FilesArgumentDescription\" xml:space=\"preserve\">\n    <value>File(s) to sign.</value>\n  </data>\n  <data name=\"InvalidBaseDirectoryValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be a fully rooted directory path.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</comment>\n  </data>\n  <data name=\"InvalidCertificateFingerprintValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</comment>\n  </data>\n  <data name=\"InvalidDigestValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</value>\n    <comment>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</comment>\n  </data>\n  <data name=\"InvalidFileValue\" xml:space=\"preserve\">\n    <value>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</value>\n  </data>\n  <data name=\"InvalidMaxConcurrencyValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be a number value greater than or equal to 1.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</comment>\n  </data>\n  <data name=\"InvalidHttpsUrlValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be an absolute HTTPS URL.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</comment>\n  </data>\n  <data name=\"InvalidUrlValue\" xml:space=\"preserve\">\n    <value>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</comment>\n  </data>\n  <data name=\"ManagedIdentityClientIdOptionDescription\" xml:space=\"preserve\">\n    <value>The client id of a user assigned ManagedIdentity.</value>\n  </data>\n  <data name=\"ManagedIdentityOptionDescription\" xml:space=\"preserve\">\n    <value>Managed identity to authenticate to Azure Key. (obsolete)</value>\n  </data>\n  <data name=\"ManagedIdentityOptionObsolete\" xml:space=\"preserve\">\n    <value>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</value>\n  </data>\n  <data name=\"ManagedIdentityResourceIdOptionDescription\" xml:space=\"preserve\">\n    <value>The resource id of a user assigned ManagedIdentity.</value>\n  </data>\n  <data name=\"MaxConcurrencyOptionDescription\" xml:space=\"preserve\">\n    <value>Maximum concurrency.</value>\n  </data>\n  <data name=\"MissingFileValue\" xml:space=\"preserve\">\n    <value>A file or glob is required.</value>\n  </data>\n  <data name=\"NoFilesToSign\" xml:space=\"preserve\">\n    <value>No inputs found to sign.</value>\n  </data>\n  <data name=\"OutputOptionDescription\" xml:space=\"preserve\">\n    <value>Output file or directory. If omitted, input files will be overwritten.</value>\n  </data>\n  <data name=\"PublisherNameOptionDescription\" xml:space=\"preserve\">\n    <value>Publisher name (ClickOnce).</value>\n    <comment>ClickOnce is a Microsoft deployment technology.</comment>\n  </data>\n  <data name=\"SignCommandDescription\" xml:space=\"preserve\">\n    <value>Sign CLI</value>\n  </data>\n  <data name=\"SomeFilesDoNotExist\" xml:space=\"preserve\">\n    <value>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</comment>\n  </data>\n  <data name=\"TenantIdOptionDescription\" xml:space=\"preserve\">\n    <value>Tenant ID to authenticate to Azure.</value>\n  </data>\n  <data name=\"TimestampDigestOptionDescription\" xml:space=\"preserve\">\n    <value>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</value>\n    <comment>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</comment>\n  </data>\n  <data name=\"TimestampUrlOptionDescription\" xml:space=\"preserve\">\n    <value>RFC 3161 timestamp server URL.</value>\n    <comment>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</comment>\n  </data>\n  <data name=\"VerbosityOptionDescription\" xml:space=\"preserve\">\n    <value>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</value>\n    <comment>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</comment>\n  </data>\n  <data name=\"x86NotSupported\" xml:space=\"preserve\">\n    <value>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</value>\n  </data>\n  <data name=\"MsvcrtNotDetected\" xml:space=\"preserve\">\n    <value>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</value>\n    <comment>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</comment>\n  </data>\n  <data name=\"CredentialTypeOptionDescription\" xml:space=\"preserve\">\n    <value>Azure credential type that will be used. This defaults to DefaultAzureCredential.</value>\n  </data>\n  <data name=\"TrustedSigningCommandObsolete\" xml:space=\"preserve\">\n    <value>The trusted-signing command is obsolete. Use the artifact-signing command instead.</value>\n  </data>\n</root>\n"
  },
  {
    "path": "src/Sign.Cli/Sign.Cli.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>sign</AssemblyName>\n    <IsPackable>true</IsPackable>\n    <IsShipping>true</IsShipping>\n    <OutputType>Exe</OutputType>\n    <PackageDescription>Sign CLI</PackageDescription>\n    <PackageReadmeFile>PACKAGE.md</PackageReadmeFile>\n    <PackAsTool>true</PackAsTool>\n    <RollForward>Major</RollForward>\n    <RootNamespace>Sign.Cli</RootNamespace>\n    <SelfContained>false</SelfContained>\n    <ToolCommandName>sign</ToolCommandName>\n    <!-- Clear RID inherited from Directory.Build.props so dotnet pack produces\n         tools/net8.0/any/ layout for cross-platform tool restore (issue #984). -->\n    <RuntimeIdentifier />\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.CommandLine\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Sign.Core\\Sign.Core.csproj\" />\n    <ProjectReference Include=\"..\\Sign.SignatureProviders.CertificateStore\\Sign.SignatureProviders.CertificateStore.csproj\" />\n    <ProjectReference Include=\"..\\Sign.SignatureProviders.KeyVault\\Sign.SignatureProviders.KeyVault.csproj\" />\n    <ProjectReference Include=\"..\\Sign.SignatureProviders.ArtifactSigning\\Sign.SignatureProviders.ArtifactSigning.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Sign.Cli.Test\" />\n  </ItemGroup>\n\n  <Target Name=\"VerifyNuGetPackage\" AfterTargets=\"Pack\">\n    <PropertyGroup>\n      <PowerShellFilePath Condition=\" '$(PowerShellFilePath)' == '' \">%WINDIR%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe</PowerShellFilePath>\n      <ScriptFilePath Condition=\" '$(ScriptFilePath)' == '' \">$(RepositoryRootDirectory)\\scripts\\VerifyNuGetPackage.ps1</ScriptFilePath>\n    </PropertyGroup>\n\n    <Exec Command=\"$(PowerShellFilePath) -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -Command &quot;&amp; { &amp;'$(ScriptFilePath)' '$(ArtifactsShippingPackagesDir)' } &quot;\" LogStandardErrorAsError=\"true\" />\n  </Target>\n\n  <ItemGroup>\n    <Content Include=\"$(RepositoryRootDirectory)\\LICENSE.txt\">\n      <Pack>true</Pack>\n      <PackagePath>\\</PackagePath>\n    </Content>\n    <Content Include=\"appsettings.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n    <Content Include=\"PACKAGE.md\">\n      <Pack>true</Pack>\n      <PackagePath>\\</PackagePath>\n    </Content>\n    <Content Include=\"$(RepositoryRootDirectory)\\THIRD-PARTY-NOTICES.txt\">\n      <Pack>true</Pack>\n      <PackagePath>\\</PackagePath>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"TrustedSigningResources.Designer.cs\">\n      <DependentUpon>TrustedSigningResources.resx</DependentUpon>\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n    </Compile>\n    <Compile Update=\"AzureKeyVaultResources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>AzureKeyVaultResources.resx</DependentUpon>\n    </Compile>\n    <Compile Update=\"CertificateStoreResources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>CertificateStoreResources.resx</DependentUpon>\n    </Compile>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n    <Compile Update=\"ArtifactSigningResources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>ArtifactSigningResources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"TrustedSigningResources.resx\">\n      <LastGenOutput>TrustedSigningResources.Designer.cs</LastGenOutput>\n      <Generator>ResXFileCodeGenerator</Generator>\n    </EmbeddedResource>\n    <EmbeddedResource Update=\"AzureKeyVaultResources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>AzureKeyVaultResources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n    <EmbeddedResource Update=\"CertificateStoreResources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>CertificateStoreResources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n    <EmbeddedResource Update=\"ArtifactSigningResources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>ArtifactSigningResources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Sign.Cli/SignCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Sign.Core;\n\nnamespace Sign.Cli\n{\n    internal sealed class SignCommand : RootCommand\n    {\n        internal SignCommand(IServiceProviderFactory? serviceProviderFactory = null)\n            : base(Resources.SignCommandDescription)\n        {\n            CodeCommand codeCommand = new();\n            serviceProviderFactory ??= new ServiceProviderFactory();\n\n            Subcommands.Add(codeCommand);\n\n            AzureKeyVaultCommand azureKeyVaultCommand = new(\n                codeCommand,\n                serviceProviderFactory);\n\n            codeCommand.Subcommands.Add(azureKeyVaultCommand);\n\n            CertificateStoreCommand certificateStoreCommand = new(\n                codeCommand,\n                serviceProviderFactory);\n\n            codeCommand.Subcommands.Add(certificateStoreCommand);\n\n            TrustedSigningCommand trustedSigningCommand = new(\n                codeCommand,\n                serviceProviderFactory);\n\n            codeCommand.Subcommands.Add(trustedSigningCommand);\n\n            ArtifactSigningCommand artifactSigningCommand = new(\n                codeCommand,\n                serviceProviderFactory);\n\n            codeCommand.Subcommands.Add(artifactSigningCommand);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/StandardStreamWriterExtensions.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\n\nnamespace Sign.Cli\n{\n    internal static class StandardStreamWriterExtensions\n    {\n        internal static void WriteFormattedLine(this TextWriter writer, string format, params object[] options)\n        {\n            string[] formattedOptions = options\n                .Select(option => $\"{((dynamic)option).Name}\")\n                .ToArray();\n\n            writer.WriteLine(string.Format(CultureInfo.InvariantCulture, format, formattedOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/TemporaryConsoleEncoding.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Text;\n\nnamespace Sign.Cli\n{\n    internal sealed class TemporaryConsoleEncoding : IDisposable\n    {\n        private readonly Encoding _defaultInputEncoding;\n        private readonly Encoding _defaultOutputEncoding;\n\n        internal TemporaryConsoleEncoding()\n        {\n            _defaultInputEncoding = Console.InputEncoding;\n            _defaultOutputEncoding = Console.OutputEncoding;\n\n            Console.InputEncoding = Encoding.UTF8;\n            Console.OutputEncoding = Encoding.UTF8;\n        }\n\n        public void Dispose()\n        {\n            Console.InputEncoding = _defaultInputEncoding;\n            Console.OutputEncoding = _defaultOutputEncoding;\n\n            GC.SuppressFinalize(this);\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Cli/TrustedSigningCommand.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Azure.CodeSigning;\nusing Azure.CodeSigning.Extensions;\nusing Azure.Core;\nusing Microsoft.Extensions.Azure;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\nusing Sign.SignatureProviders.ArtifactSigning;\n\nnamespace Sign.Cli\n{\n    internal sealed class TrustedSigningCommand : Command\n    {\n        internal Option<Uri> EndpointOption { get; }\n        internal Option<string> AccountOption { get; }\n        internal Option<string> CertificateProfileOption { get; }\n        internal AzureCredentialOptions AzureCredentialOptions { get; } = new();\n\n        internal Argument<List<string>?> FilesArgument { get; }\n\n        internal TrustedSigningCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)\n            : base(\"trusted-signing\", TrustedSigningResources.CommandDescription)\n        {\n            ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));\n            ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));\n\n            EndpointOption = new Option<Uri>(\"--trusted-signing-endpoint\", \"-tse\")\n            {\n                CustomParser = CodeCommand.ParseHttpsUrl,\n                Description = TrustedSigningResources.EndpointOptionDescription,\n                Required = true\n            };\n            AccountOption = new Option<string>(\"--trusted-signing-account\", \"-tsa\")\n            {\n                Description = TrustedSigningResources.AccountOptionDescription,\n                Required = true\n            };\n            CertificateProfileOption = new Option<string>(\"--trusted-signing-certificate-profile\", \"-tscp\")\n            {\n                Description = TrustedSigningResources.CertificateProfileOptionDescription,\n                Required = true\n            };\n            FilesArgument = new Argument<List<string>?>(\"file(s)\")\n            {\n                Description = Resources.FilesArgumentDescription,\n                Arity = ArgumentArity.OneOrMore\n            };\n\n            Options.Add(EndpointOption);\n            Options.Add(AccountOption);\n            Options.Add(CertificateProfileOption);\n            AzureCredentialOptions.AddOptionsToCommand(this);\n\n            Arguments.Add(FilesArgument);\n\n            SetAction((ParseResult parseResult, CancellationToken cancellationToken) =>\n            {\n                Console.Out.WriteLine(Resources.TrustedSigningCommandObsolete);\n\n                List<string>? filesArgument = parseResult.GetValue(FilesArgument);\n\n                if (filesArgument is not { Count: > 0 })\n                {\n                    Console.Error.WriteLine(Resources.MissingFileValue);\n\n                    return Task.FromResult(ExitCode.InvalidOptions);\n                }\n\n                TokenCredential? credential = AzureCredentialOptions.CreateTokenCredential(parseResult);\n\n                if (credential is null)\n                {\n                    return Task.FromResult(ExitCode.Failed);\n                }\n\n                // Some of the options are required and that is why we can safely use\n                // the null-forgiving operator (!) to simplify the code.\n                Uri endpointUrl = parseResult.GetValue(EndpointOption)!;\n                string accountName = parseResult.GetValue(AccountOption)!;\n                string certificateProfileName = parseResult.GetValue(CertificateProfileOption)!;\n\n                serviceProviderFactory.AddServices(services =>\n                {\n                    services.AddAzureClients(builder =>\n                    {\n                        builder.AddCertificateProfileClient(endpointUrl);\n                        builder.UseCredential(credential);\n                        builder.ConfigureDefaults(options => options.Retry.Mode = RetryMode.Exponential);\n                    });\n\n                    services.AddSingleton<ArtifactSigningService>(serviceProvider =>\n                    {\n                        return new ArtifactSigningService(\n                            serviceProvider.GetRequiredService<CertificateProfileClient>(),\n                            accountName,\n                            certificateProfileName,\n                            serviceProvider.GetRequiredService<ILogger<ArtifactSigningService>>());\n                    });\n                });\n\n                ArtifactSigningServiceProvider trustedSigningServiceProvider = new();\n\n                return codeCommand.HandleAsync(parseResult, serviceProviderFactory, trustedSigningServiceProvider, filesArgument);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/TrustedSigningResources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Cli {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class TrustedSigningResources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal TrustedSigningResources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Cli.TrustedSigningResources\", typeof(TrustedSigningResources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Trusted Signing Account name..\n        /// </summary>\n        internal static string AccountOptionDescription {\n            get {\n                return ResourceManager.GetString(\"AccountOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Certificate Profile name..\n        /// </summary>\n        internal static string CertificateProfileOptionDescription {\n            get {\n                return ResourceManager.GetString(\"CertificateProfileOptionDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use Trusted Signing. (obsolete, use artifact-signing instead).\n        /// </summary>\n        internal static string CommandDescription {\n            get {\n                return ResourceManager.GetString(\"CommandDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in..\n        /// </summary>\n        internal static string EndpointOptionDescription {\n            get {\n                return ResourceManager.GetString(\"EndpointOptionDescription\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/TrustedSigningResources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"AccountOptionDescription\" xml:space=\"preserve\">\n    <value>The Trusted Signing Account name.</value>\n  </data>\n  <data name=\"CertificateProfileOptionDescription\" xml:space=\"preserve\">\n    <value>The Certificate Profile name.</value>\n  </data>\n  <data name=\"CommandDescription\" xml:space=\"preserve\">\n    <value>Use Trusted Signing. (obsolete, use artifact-signing instead)</value>\n  </data>\n  <data name=\"EndpointOptionDescription\" xml:space=\"preserve\">\n    <value>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</value>\n  </data>\n</root>\n"
  },
  {
    "path": "src/Sign.Cli/appsettings.json",
    "content": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Azure.Core\": \"Error\",\n            \"Azure.Identity\": \"Error\"\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Název účtu Artifact Signing</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Název profilu certifikátu</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Použijte Artifact Signing.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Koncový bod účtu Artifact Signing. Hodnota musí být identifikátor URI, který odpovídá oblasti, ve které jste vytvořili účet Artifact Signing a profil certifikátu.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Der Name des Artefaktsignatur-Kontos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Der Zertifikatprofilname.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Artefaktsignatur verwenden</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Der Endpunkt des Kontos der Artefaktsignatur. Der Wert muss ein URI sein, der der Region entspricht, in der Ihr Konto der Artefaktsignatur und das Zertifikatprofil erstellt wurden.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Nombre de la cuenta de firma de artefactos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nombre del perfil de certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Use la firma de artefactos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Punto de conexión de la cuenta de firma de artefactos. El valor debe ser un URI que se alinee con la región en la que se crearon la cuenta de firma de artefactos y el perfil de certificado.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Nom du compte de Signature d'artefacts.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nom du profil de certificat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Utilisez la Signature d'artefacts.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Point de terminaison du compte de Signature d'artefacts. La valeur doit être un URI correspondant à la région dans laquelle votre compte de Signature d'artefacts et votre profil de certificat ont été créés.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Nome dell'account Firma artefatti.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nome profilo certificato.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Usare Firma artefatti.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Endpoint dell'account di Firma artefatti. Il valore deve essere un URI allineato all'area in cui sono stati creati l'account Firma artefatti e il profilo del certificato.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Artifact Signing アカウント名です。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">証明書プロファイル名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Artifact Signing を使用します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Artifact Signing アカウントのエンドポイントです。この値は、Artifact Signing アカウントと証明書プロファイルが作成されたリージョンに合った URI である必要があります。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Artifact Signing 계정 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">인증서 프로필 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Artifact Signing을 사용합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Artifact Signing 계정 엔드포인트입니다. 값은 Artifact Signing 계정 및 인증서 프로필을 만든 지역에 맞는 URI여야 합니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Nazwa konta podpisywania artefaktu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nazwa profilu certyfikatu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Użyj podpisywania artefaktu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Punkt końcowy konta podpisywania artefaktu. Wartość musi być identyfikatorem URI, który jest zgodny z regionem, w ramach którego utworzono konto podpisywania artefaktu i profil certyfikatu.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">O nome da Conta de Assinatura de Artefatos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">O nome do Perfil de Certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Use a Assinatura de Artefatos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">O ponto de extremidade da Conta de Assinatura de Artefatos. O valor deve ser um URI que se alinhe à região em que sua Conta de Assinatura de Artefatos e o Perfil de Certificado foram criados.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Имя учетной записи для подписания артефактов.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Имя профиля сертификата.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Использование подписания артефактов.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Конечная точка учетной записи для подписания артефактов. Значение — универсальный код ресурса (URI), соответствующий региону, в котором созданы учетная запись для подписания артефактов и профиль сертификата.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Yapıt İmzalama Hesabı adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Sertifika Profili adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">Yapıt İmzalama'yı kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Yapıt İmzalama Hesabı uç noktası. Değer, Yapıt İmzalama Hesabınızın ve Sertifika Profilinizin oluşturulduğu bölgeyle uyumlu bir URI olmalıdır.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">工件签名帐户名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">证书配置文件名称。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">使用工件签名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">工件签名帐户终结点。该值必须是与创建工件签名帐户和证书配置文件的区域相对应的 URI。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/ArtifactSigningResources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../ArtifactSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Artifact Signing Account name.</source>\n        <target state=\"translated\">Artifact Signing 帳戶名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">憑證設定檔名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Artifact Signing.</source>\n        <target state=\"translated\">使用 Artifact Signing。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Artifact Signing Account endpoint. The value must be a URI that aligns to the region that your Artifact Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Artifact Signing 帳戶端點。值必須是 URI，且與您的 Artifact Signing 帳戶和憑證設定檔建立區域一致。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Název certifikátu v Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Podepisování ClickOnce prostřednictvím starší verze alternativního řešení .clickonce ZIP se už nepodporuje. Projděte si dokumentaci.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Použijte Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">Adresa URL musí obsahovat pouze protokol a hostitele. (např. https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Adresa URL musí být absolutní adresa URL protokolu HTTPS pro Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Adresa URL Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Name des Zertifikats in Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Die ClickOnce-Signierung über die Legacy-.clickonce-ZIP-Problemumgehung wird nicht mehr unterstützt. Siehe Dokumentation.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Verwenden Sie Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">Die URL darf nur das Protokoll und den Host enthalten. (Beispiel: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Die URL muss eine absolute HTTPS-URL zu einem Azure Key Vault sein.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL zu einem Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Nombre del certificado en Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Ya no se admite la firma ClickOnce a través de la solución zip heredada .clickonce. Consulte la documentación.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Use Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">La dirección URL solo debe contener el protocolo y el host. (por ejemplo: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">La dirección URL debe ser una dirección URL HTTPS absoluta a un Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Dirección URL a un Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Nom du certificat dans Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">La signature ClickOnce via la solution de contournement zip .clickonce héritée n’est plus prise en charge. Consulter la documentation.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Utilisez Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">L’URL doit contenir uniquement le protocole et l’hôte. (par exemple : https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">L’URL doit être une URL HTTPS absolue vers un coffre-fort Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL d’un Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Nome del certificato in Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">La firma ClickOnce tramite la soluzione alternativa legacy .clickonce ZIP non è più supportata. Vedere la documentazione.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Usare Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">L'URL deve contenere solo il protocollo e l'host. (ad esempio: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">L'URL deve essere un URL HTTPS assoluto per Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL a un Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault 内の証明書の名前。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">従来の .clickonce ZIP 回避策による ClickOnce 署名はサポートされなくなりました。ドキュメントを参照してください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault を使用してください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL にはプロトコルとホストのみを含めなければなりません。(例: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL は、Azure Key Vault への絶対 HTTPS URL である必要があります。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault への URL。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault의 인증서 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">레거시 .clickonce ZIP 해결 방법을 통한 ClickOnce 서명은 더 이상 지원되지 않습니다. 설명서를 참조하세요.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault를 사용합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL은 프로토콜과 호스트만 포함해야 합니다. (예: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL은 Azure Key Vault의 절대 HTTPS URL이어야 합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault에 대한 URL입니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Nazwa certyfikatu w usłudze Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Podpisywanie clickOnce za pośrednictwem starszego obejścia .clickonce ZIP nie jest już obsługiwane. Zobacz dokumentację.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Użyj usługi Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">Adres URL może zawierać tylko protokół i hosta. (np. https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Adres URL musi być bezwzględnym adresem URL HTTPS do usługi Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Adres URL do usługi Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Nome do certificado no Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Não há mais suporte para a assinatura do ClickOnce por meio da solução alternativa .clickonce ZIP herdada. Consulte a documentação.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Use o Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">A URL deve conter somente o protocolo e o host. (por exemplo: https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">A URL deve ser uma URL HTTPS absoluta para um Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL para um Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Имя сертификата в Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Подписание ClickOnce с помощью устаревшего обходного пути .clickonce ZIP больше не поддерживается. См. документацию.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Использование Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL-адрес должен содержать только протокол и хост. (например, https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL-адрес должен быть абсолютным URL-адресом HTTPS для Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL-адрес для Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault’taki sertifikanın adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">Eski .clickonce ZIP geçici çözümü aracılığıyla ClickOnce imzalama işlemi artık desteklenmiyor. Belgelere bakın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault’u kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL yalnızca protokolü ve ana bilgisayarı içermeli. (ör. https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL, bir Azure Key Vault'un mutlak HTTPS URL'si olmalıdır.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault URL’si.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault 中的证书名称。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">不再支持通过旧版 .clickonce ZIP 解决方法进行 ClickOnce 签名。参阅文档。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">使用 Azure Key Vault。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL 只能包含协议和主机。(，例如： https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL 必须是指向 Azure Key Vault 的绝对 HTTPS URL。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">指向 Azure Key Vault 的 URL。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/AzureKeyVaultResources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../AzureKeyVaultResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateOptionDescription\">\n        <source>Name of the certificate in Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault 中的憑證名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClickOnceExtensionNotSupported\">\n        <source>ClickOnce signing via the legacy .clickonce ZIP workaround is no longer supported. See documentation.</source>\n        <target state=\"translated\">已不再支援透過舊版 .clickonce ZIP 因應措施進行 ClickOnce 簽署。請參閱文件。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Azure Key Vault.</source>\n        <target state=\"translated\">使用 Azure Key Vault。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidKeyVaultUrl\">\n        <source>URL must only contain the protocol and host. (e.g.: https://&lt;vault-name&gt;.vault.azure.net/)</source>\n        <target state=\"translated\">URL 只能包含通訊協定和主機。(例如： https://&lt;vault-name&gt;.vault.azure.net/)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>URL must be an absolute HTTPS URL to an Azure Key Vault.</source>\n        <target state=\"translated\">URL 必須是指向 Azure Key Vault 的絕對 HTTPS URL。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UrlOptionDescription\">\n        <source>URL to an Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault 的 URL。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Zprostředkovatel kryptografických služeb obsahující kontejner privátního klíče. Vyžaduje se /k nebo /km.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Kontejner privátního klíče v úložišti uživatele.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Kontejner privátního klíče v úložišti počítače.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Poskytlo se několik kontejnerů privátních klíčů. Pro úložiště uživatele použijte /k a pro úložiště počítače použijte /km.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Při použití /csp chybí kontejner privátního klíče. K poskytnutí kontejneru klíčů použijte /k nebo /km.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Kryptografický otisk SHA1 použitý pro přístup k certifikátu z úložiště certifikátů (VSIX).</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Kryptografiedienstanbieter, der den privaten Schlüsselcontainer enthält. Erfordert /k oder /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Container mit privatem Schlüssel im Benutzerspeicher</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Container mit privatem Schlüssel im Computerspeicher</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Es wurden mehrere Container mit privatem Schlüssel bereitgestellt. Verwenden Sie entweder \"/k\" für Benutzerspeicher oder \"/km\" für Computerspeicher.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Der Container für den privaten Schlüssel fehlt bei Verwendung von \"/csp\". Verwenden Sie \"/k\" oder \"/km\", um einen Schlüsselcontainer bereitzustellen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">SHA1-Fingerabdruck für den Zugriff auf ein Zertifikat aus einem Zertifikatspeicher (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Proveedor de servicios criptográficos que contiene el contenedor de claves privadas. Requiere /k o /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Contenedor de claves privadas en el almacén de usuarios</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Contenedor de claves privadas en el almacén de máquinas</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Se proporcionaron varios contenedores de clave privada. Use /k para almacenes de usuarios o /km para almacenes de máquinas</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Falta el contenedor de clave privada al usar /csp. Use /k o /km para proporcionar un contenedor de claves.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Huella digital SHA1 usada para obtener acceso a un certificado desde un almacén de certificados (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Fournisseur de services de chiffrement contenant le conteneur de clé privée. Nécessite /k ou /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Conteneur de clés privées dans le magasin d’utilisateurs</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Conteneur de clés privées dans le magasin d’ordinateurs</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Plusieurs conteneurs de clé privée ont été fournis. Utiliser /k pour les magasins d’utilisateurs ou /km pour les magasins d’ordinateurs</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Le conteneur de clé privée est manquant lors de l’utilisation de /csp. Utilisez /k ou /km pour fournir un conteneur de clé.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Empreinte SHA-1 utilisée pour accéder à un certificat à partir d’un magasin de certificats (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Provider del servizio di crittografia contenente il contenitore di chiavi private. Richiede /k o /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Contenitore di chiavi private nell'archivio utenti</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Contenitore di chiavi private nell'archivio computer</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Sono stati specificati più contenitori di chiavi private. Utilizzare /k per gli archivi utente o /km per gli archivi computer</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Contenitore di chiavi private mancante durante l'utilizzo di /csp. Usare /k o /km per specificare un contenitore di chiavi.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Identificazione personale SHA1 usata per accedere a un certificato da un archivio certificati (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">秘密キー コンテナーを含む暗号化サービス プロバイダー。/k または /km が必要です</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">ユーザー ストア内の秘密キー コンテナー</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">コンピューター ストア内の秘密キー コンテナー</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">複数の秘密キー コンテナーが提供されています。ユーザー ストアには /k、コンピューター ストアの場合は /km を使用します</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp の使用中に秘密キー コンテナーが見つかりません。キー コンテナーを指定するには、/k または /km を使用します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">証明書ストア (VSIX) から証明書にアクセスするために使用される SHA1 拇印</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">프라이빗 키 컨테이너를 포함하는 암호화 서비스 공급자입니다. /k 또는 /km 필요</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">사용자 저장소의 프라이빗 키 컨테이너</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">컴퓨터 저장소의 프라이빗 키 컨테이너</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">여러 프라이빗 키 컨테이너가 제공되었습니다. 사용자 저장소에는 /k를, 컴퓨터 저장소에는 /km 사용</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp를 사용하는 동안 프라이빗 키 컨테이너가 없습니다. /k 또는 /km를 사용하여 키 컨테이너를 제공합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">VSIX(인증서 저장소)에서 인증서에 액세스하는 데 사용되는 SHA1 지문</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Dostawca usług kryptograficznych zawierający kontener kluczy prywatnych. Wymaga opcji /k lub /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Kontener kluczy prywatnych w magazynie użytkowników</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Kontener kluczy prywatnych w magazynie komputerów</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Podano wiele kontenerów kluczy prywatnych. Użyj opcji /k dla magazynów użytkowników lub opcji /km dla magazynów komputerów</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Brak kontenera kluczy prywatnych podczas używania opcji /csp. Użyj opcji /k lub /km, aby podać kontener kluczy.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Odcisk palca SHA1 używany do uzyskiwania dostępu do certyfikatu z magazynu certyfikatów (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Provedor de Serviços Criptográficos que contém o contêiner de chave privada. Requer /k ou /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Contêiner de chave privada no repositório do usuário</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Contêiner de chave privada no repositório do computador</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Vários contêineres de chave privada fornecidos. Usar /k para repositórios de usuários ou /km para repositórios de computadores</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Contêiner de chave privada ausente ao usar /csp. Use /k ou /km para fornecer um contêiner de chave.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Impressão digital SHA1 usada para acessar um certificado de um repositório de certificados (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Поставщик служб шифрования, содержащий контейнер закрытого ключа. Требуется /k или /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Контейнер закрытого ключа в хранилище пользователя</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Контейнер закрытого ключа в хранилище компьютера</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Предоставлено несколько контейнеров закрытых ключей. Используйте /k для хранилищ пользователей или /km для хранилищ компьютеров</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Отсутствует контейнер закрытого ключа при использовании /csp. Используйте /k или /km для предоставления контейнера ключей.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Отпечаток SHA1, используемый для доступа к сертификату из хранилища сертификатов (VSIX)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">Özel anahtar kapsayıcısını içeren Şifreleme Hizmeti Sağlayıcısı. /k veya /km gerektirir</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">Kullanıcı deposundaki özel anahtar kapsayıcısı</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">Makine deposundaki özel anahtar kapsayıcısı</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">Birden çok özel anahtar kapsayıcısı sağlandı. Kullanıcı depoları için /k veya makine depoları için /km kullanın</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp kullanılırken özel anahtar kapsayıcısı eksik. Anahtar kapsayıcısı sağlamak için /k veya /km kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">Sertifika deposundan (VSIX) bir sertifikaya erişmek için SHA1 parmak izi kullanıldı</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">包含私钥容器的加密服务提供程序。需要 /k 或 /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">用户存储中的私钥容器</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">计算机存储中的私钥容器</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">提供了多个私钥容器。对用户存储使用 /k，或者对计算机存储使用 /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">使用 /csp 时缺少私钥容器。使用 /k 或 /km 提供密钥容器。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">用于访问证书存储(VSIX)中的证书的 SHA1 直纹</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertManagerResources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../CertManagerResources.resx\">\n    <body>\n      <trans-unit id=\"CSPOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k or /km</source>\n        <target state=\"translated\">包含私密金鑰容器的加密服務提供者。需要 /k 或 /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container in the user store</source>\n        <target state=\"translated\">使用者存放區中的私密金鑰</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MachineKeyContainerOptionDescription\">\n        <source>Private key container in the machine store</source>\n        <target state=\"translated\">機器存放區中的私密金鑰</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores</source>\n        <target state=\"translated\">已提供多個私密金鑰。使用者存放區使用 /k，機器存放區則使用 /km</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">使用 /csp 時遺漏私密金鑰容器。使用 /k 或 /km 來提供金鑰容器。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SHA1ThumbprintOptionDescription\">\n        <source>SHA1 thumprint used to access a certificate from a certificate store (VSIX)</source>\n        <target state=\"translated\">用以從憑證存放區 (VSIX) 存取憑證的 SHA1 指紋</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Soubor PFX, P7B nebo CER obsahující certifikát a potenciálně privátní klíč.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Otisk SHA sloužící k identifikaci certifikátu</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Heslo pro soubor certifikátu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Podepsat obsah kontejneru</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Zprostředkovatel kryptografických služeb obsahující kontejner privátního klíče. Vyžaduje /k a volitelně /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Povolit interakce uživatelů (například dialogové okno) při přístupu k privátnímu klíči.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Název kontejneru privátního klíče.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Chybí zprostředkovatel kryptografických služeb.  K určení zprostředkovatele kryptografických služeb použijte /csp.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Chybí název kontejneru privátního klíče. Název kontejneru klíče zadejte pomocí /k.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Použijte kontejner privátního klíče na úrovni počítače.  (Výchozí hodnota je na úrovni uživatele.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">PFX-, P7B- oder CER-Datei, die ein Zertifikat und möglicherweise einen privaten Schlüssel enthält.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">SHA-Fingerabdruck zum Identifizieren eines Zertifikats.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Kennwort für Zertifikatdatei.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Inhalt des Containers signieren.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Kryptografiedienstanbieter, der den privaten Schlüsselcontainer enthält. Erfordert /k und optional /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Benutzerinteraktionen (z. B. ein Dialogfeld) zulassen, wenn auf einen privaten Schlüssel zugegriffen wird.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Name des privaten Schlüsselcontainers.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Kryptografiedienstanbieter fehlt.  Verwenden Sie \"/csp\", um einen CSP anzugeben.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Der Name des privaten Schlüsselcontainers fehlt. Verwenden Sie /k, um einen Schlüsselcontainernamen anzugeben.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Verwenden Sie einen Container mit privatem Schlüssel auf Computerebene.  (Der Standardwert ist Benutzerebene.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Archivo PFX, P7B o CER que contiene un certificado y una clave privada potencialmente.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Huella digital SHA usada para identificar un certificado.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Contraseña del archivo de certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Firmar el contenido del contenedor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Proveedor de servicios criptográficos que contiene el contenedor de claves privadas. Requiere /k y, opcionalmente, /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Permitir interacciones de usuario (como un cuadro de diálogo) cuando se tiene acceso a una clave privada.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Nombre de contenedor de clave privada.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Falta el proveedor de servicios criptográficos.  Use /csp para especificar un CSP.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Falta el nombre de contenedor de claves privadas. Use /k para especificar un nombre de contenedor de claves.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Use un contenedor de claves privadas de nivel de máquina.  (El valor predeterminado es de nivel de usuario).</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Fichier PFX, P7B ou CER contenant un certificat et éventuellement une clé privée.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Empreinte digitale SHA utilisée pour identifier un certificat.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Mot de passe du fichier du certificat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Signer le contenu du conteneur.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Fournisseur de services de chiffrement contenant le conteneur de clé privée. Nécessite /k et éventuellement /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Autorisez les interactions utilisateur (par exemple, une boîte de dialogue) lorsqu’une clé privée est accessible.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Nom de conteneur de clé privée.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Le fournisseur de services de chiffrement est manquant.  Utilisez /csp pour spécifier un fournisseur de solutions Cloud.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Le nom de conteneur de clé privée est manquant. Utilisez /k pour spécifier un nom de conteneur de clé.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Utilisez un conteneur de clé privée au niveau de l’ordinateur.  (La valeur par défaut est au niveau de l’utilisateur.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">PFX, P7B o CER file contenente un certificato e potenzialmente una chiave privata.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Impronta digitale SHA usata per identificare un certificato.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Password per file certificato.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Contenuti contenitore firme.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Provider del servizio di crittografia contenente il contenitore di chiavi private. Richiede /k e facoltativamente /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Consenti interazioni utente (ad esempio una finestra di dialogo) quando si accede a una chiave privata.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Nome del contenitore di chiavi private.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Provider del servizio di crittografia mancante.  Utilizzare /csp per specificare un CSP.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Nome del contenitore di chiavi private mancante. Usare /k per specificare il nome di un contenitore di chiavi.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Usare un contenitore di chiavi private a livello di computer.  (Il valore predefinito è a livello di utente).</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">証明書と潜在的に秘密キーを含む PFX、P7B、または CER ファイル。</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">証明書の識別に使用される SHA フィンガープリント。</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">証明書ファイルのパスワード。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">コンテナーの内容に署名します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">秘密キー コンテナーを含む暗号化サービス プロバイダー。/k および必要に応じて /km が必要です。</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">秘密キーにアクセスするときにユーザーの操作 (ダイアログ ボックスなど) を許可します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">秘密キー コンテナー名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">暗号化サービス プロバイダーがありません。/csp を使用して CSP を指定します。</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">秘密キー コンテナー名がありません。キー コンテナー名を指定するには、/k を使用します。</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">コンピューター レベルの秘密キー コンテナーを使用します。(既定値はユーザー レベルです)。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">인증서와 잠재적으로 프라이빗 키가 포함된 PFX, P7B 또는 CER 파일입니다.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">인증서를 식별하는 데 사용되는 SHA 지문입니다.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">인증서 파일의 암호입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">컨테이너 내용 서명.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">프라이빗 키 컨테이너를 포함하는 암호화 서비스 공급자입니다. /k 및 선택적으로 /km이 필요합니다.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">프라이빗 키에 액세스할 때 사용자 상호 작용(예: 대화 상자)을 허용합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">프라이빗 키 컨테이너 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">암호화 서비스 공급자가 없습니다.  /csp를 사용하여 CSP를 지정합니다.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">프라이빗 키 컨테이너 이름이 없습니다. /k를 사용하여 키 컨테이너 이름을 지정합니다.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">컴퓨터 수준 프라이빗 키 컨테이너를 사용합니다.  (기본값은 사용자 수준입니다.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Plik PFX, P7B lub CER zawierający certyfikat i potencjalnie klucz prywatny.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Odcisk palca SHA używany do identyfikowania certyfikatu.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Hasło dla pliku certyfikatu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Podpisz zawartość kontenera.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Dostawca usług kryptograficznych zawierający kontener kluczy prywatnych. Wymaga opcji /k i opcjonalnie /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Zezwalaj na interakcje użytkownika (takie jak okno dialogowe) po uzyskaniu dostępu do klucza prywatnego.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Nazwa kontenera kluczy prywatnych.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Brak dostawcy usług kryptograficznych.  Użyj /csp, aby określić dostawcę CSP.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Brak nazwy kontenera kluczy prywatnych. Użyj opcji /k, aby określić nazwę kontenera kluczy.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Użyj kontenera kluczy prywatnych na poziomie komputera.  (Wartość domyślna to poziom użytkownika).</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Arquivos PFX, P7B ou CER que contêm um certificado e, possivelmente, uma chave privada.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Impressão digital SHA usada para identificar um certificado.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Senha do arquivo do certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Assinar o conteúdo do contêiner.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Provedor de Serviços Criptográficos que contém o contêiner de chave privada. Requer /k e, opcionalmente, /km.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Permitir interações do usuário (como uma caixa de diálogo) quando uma chave privada for acessada.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Nome do contêiner de chave privada.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Provedor de Serviços Criptográficos ausente.  Use /csp para especificar um CSP.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Nome do contêiner de chave privada ausente. Use /k para especificar um nome de contêiner de chave.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Use um contêiner de chave privada no nível do computador.  (O padrão é o nível do usuário.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Файл PFX, P7B или CER, содержащий сертификат и, возможно, закрытый ключ.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Отпечаток SHA, используемый для идентификации сертификата.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Пароль для файла сертификата.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Подписать содержимое контейнера.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Поставщик служб шифрования, содержащий контейнер закрытого ключа. Требуется /k и /km (необязательно).</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Разрешить взаимодействие с пользователем (например, диалоговое окно) при доступе к закрытому ключу.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Имя контейнера закрытого ключа.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Отсутствует поставщик служб шифрования.  Используйте /csp, чтобы указать CSP.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Отсутствует имя контейнера закрытого ключа. Используйте /k, чтобы указать имя контейнера ключей.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Используйте контейнер закрытого ключа на уровне компьютера.  (По умолчанию используется уровень пользователя.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">Bir sertifika ve potansiyel olarak özel anahtar içeren PFX, P7B veya CER dosyası.</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">Sertifikayı tanımlamak için kullanılan SHA parmak izi.</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">Sertifika dosyasının parolası.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">Kapsayıcı içeriklerini imzalayın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">Özel anahtar kapsayıcısını içeren Şifreleme Hizmeti Sağlayıcısı. /k ve alternatif olarak /km gerektirir.</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">Özel anahtara erişildiğinde kullanıcı etkileşimlerine (iletişim kutusu gibi) izin ver.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">Özel anahtar kapsayıcısı adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">Şifreleme Hizmeti Sağlayıcısı eksik.  CSP belirtmek için /csp kullanın.</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">Özel anahtar kapsayıcısı adı eksik. Anahtar kapsayıcısı adı belirtmek için /k kullanın.</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">Makine düzeyinde özel anahtar kapsayıcısı kullanın.  (Varsayılan, kullanıcı düzeyidir.)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">包含证书和可能包含私钥的 PFX、P7B 或 CER 文件。</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">用于标识证书的 SHA 指纹。</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">证书文件的密码。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">对容器内容进行签名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">包含私钥容器的加密服务提供程序。需要 /k 和 /km (可选)。</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">访问私钥时允许用户交互(如对话框)。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">私钥容器名称。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">缺少加密服务提供程序。使用 /csp 指定 CSP。</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">缺少私钥容器名称。使用 /k 指定密钥容器名称。</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">使用计算机级私钥容器。(默认值为用户级别。)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/CertificateStoreResources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../CertificateStoreResources.resx\">\n    <body>\n      <trans-unit id=\"CertificateFileOptionDescription\">\n        <source>PFX, P7B, or CER file containing a certificate and potentially a private key.</source>\n        <target state=\"translated\">包含憑證和潛在的私用金鑰的 PFX、P7B 或 CER 檔案。</target>\n        <note>{Locked=\"PFX\", \"P7B\", \"CER\"} are file extensions.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateFingerprintOptionDescription\">\n        <source>SHA fingerprint used to identify a certificate.</source>\n        <target state=\"translated\">用以識別憑證的 SHA 指紋。</target>\n        <note>{Locked=\"SHA\"} is a cryptographic algorithm.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificatePasswordOptionDescription\">\n        <source>Password for certificate file.</source>\n        <target state=\"translated\">憑證檔案的密碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ContainersDescription\">\n        <source>Sign container contents.</source>\n        <target state=\"translated\">簽署容器內容。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CspOptionDescription\">\n        <source>Cryptographic Service Provider containing the private key container. Requires /k and optionally /km.</source>\n        <target state=\"translated\">包含私密金鑰容器的加密服務提供者。需要 /k 並選擇性地 /km。</target>\n        <note>{Locked=\"/k\", \"/km\"} are command line options.</note>\n      </trans-unit>\n      <trans-unit id=\"InteractiveDescription\">\n        <source>Allow user interactions (such as a dialog box) when a private key is accessed.</source>\n        <target state=\"translated\">當存取私密金鑰時，允許使用者互動 (例如對話方塊)。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"KeyContainerOptionDescription\">\n        <source>Private key container name.</source>\n        <target state=\"translated\">私密金鑰容器名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingCspError\">\n        <source>Cryptographic Service Provider missing.  Use /csp to specify a CSP.</source>\n        <target state=\"translated\">遺漏密碼編譯服務提供者。使用 /csp 來指定雲端解決方案提供者。</target>\n        <note>{Locked=\"/csp\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"MissingPrivateKeyContainerError\">\n        <source>Private key container name missing. Use /k to specify a key container name.</source>\n        <target state=\"translated\">遺漏私密金鑰容器名稱。使用 /k 來指定金鑰容器名稱。</target>\n        <note>{Locked=\"/k\"} is a command line option.</note>\n      </trans-unit>\n      <trans-unit id=\"UseMachineKeyContainerOptionDescription\">\n        <source>Use a machine-level private key container.  (The default is user-level.)</source>\n        <target state=\"translated\">使用機器層級私密金鑰容器。(預設為使用者等級。)</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Název aplikace (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Základní adresář pro soubory  Přepíše aktuální pracovní adresář.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Použijte úložiště certifikátů systému Windows nebo místní soubor certifikátu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID klienta pro ověření v Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Tajný kód klienta pro ověření v Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Možnosti tajného kódu klienta jsou zastaralé a již by neměly být zadány.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Podepisovat binární soubory a kontejnery.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Typ přihlašovacího údaje Azure, který se použije. Výchozí hodnota je DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Popis podpisového certifikátu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">Popis adresy URL podpisového certifikátu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algoritmus hodnoty hash pro hash souborů. Povolené hodnoty jsou sha256, sha384 a sha512.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Cesta k souboru obsahujícímu cesty k souborům, které se mají podepsat nebo vyloučit z podepisování.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Soubor nebo soubory, které se mají podepsat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Neplatná hodnota pro {0}. Hodnota musí být plně kořenová cesta k adresáři.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Neplatná hodnota pro {0}. Hodnotou musí být otisk certifikátu SHA-256, SHA-384 nebo SHA-512 (v šestnáctkovém tvaru).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Neplatná hodnota pro {0}. Hodnota musí být sha256, sha384 nebo sha512.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Cestu k souboru nelze při použití glob zakořenit. Použijte relativní cestu k pracovnímu adresáři (nebo základnímu adresáři, pokud se používá).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Neplatná hodnota pro {0}. Hodnota musí být číselná hodnota větší nebo rovna 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Neplatná hodnota pro {0}. Hodnota musí být absolutní adresa URL protokolu HTTP nebo HTTPS.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ID klienta Spravované identity přiřazené uživatelem.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Spravovaná identita pro ověření ve službě Azure Key. (zastaralé)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Možnosti -kvm a --azure-key-vault-managed-identity jsou zastaralé a už by se neměly zadávat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ID prostředku Spravované identity přiřazené uživatelem.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Maximální souběžnost.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Vyžaduje se soubor nebo glob.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Upozornění: Modul runtime Microsoft Visual C++ 14 je povinný, ale ve vašem systému nebyl zjištěn.  Stáhnout a nainstalovat z https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Nenašly se žádné vstupy, které by bylo možné podepsat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Výstupní soubor nebo adresář. Pokud je tento parametr vynechán, vstupní soubory budou přepsány.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Název vydavatele (ClickOnce)</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Podepsat rozhraní příkazového řádku</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Některé soubory neexistují.  Zkuste použít jinou hodnotu {0} nebo plně kvalifikovanou cestu k souboru.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID tenanta pro ověření v Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Algoritmus hodnoty hash pro server časového razítka RFC 3161. Povolené hodnoty jsou sha256, sha384 a sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">Adresa URL serveru časového razítka RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Příkaz trusted-signing je zastaralý. Místo toho použijte příkaz artifact-signing.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Nastaví úroveň podrobností. Povolené hodnoty jsou none, critical, error, warning, information, debug a trace.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">V současné době je podporován pouze systém Windows x64. Podívejte se na https://github.com/dotnet/sign/issues/474 týkající se podpory windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Anwendungsname (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Basisverzeichnis für Dateien.  Überschreibt das aktuelle Arbeitsverzeichnis.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Verwenden Sie den Windows-Zertifikatspeicher oder eine lokale Zertifikatdatei.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Client-ID für die Authentifizierung bei Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Geheimer Clientschlüssel für die Authentifizierung bei Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Die Optionen für geheime Clientschlüssel sind veraltet und sollten nicht mehr angegeben werden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Signieren Sie Binärdateien und Container.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Azure-Anmeldeinformationstyp, der verwendet wird. Standardmäßig ist dies DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Beschreibung des Signaturzertifikats.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">Beschreibungs-URL des Signaturzertifikats.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Digestalgorithmus zum Hashen von Dateien. Zulässige Werte sind \"sha256\", \"sha384\" und \"sha512\".</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Pfad zur Datei mit Pfaden von Dateien, die signiert oder von der Signierung ausgeschlossen werden sollen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Zu signierende Datei(en).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Ungültiger Wert für {0}. Der Wert muss ein vollständiger Stammverzeichnispfad sein.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Ungültiger Wert für {0}. Der Wert muss ein SHA-256-, SHA-384- oder SHA-512-Zertifikatfingerabdruck (hexadezimal) sein.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Ungültiger Wert für {0}. Der Wert muss \"sha256\", \"sha384\" oder \"sha512\" sein.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Der Dateipfad kann keinem Stamm zugewiesen werden, wenn ein Glob verwendet wird. Verwenden Sie einen Pfad relativ zum Arbeitsverzeichnis (oder Basisverzeichnis, falls verwendet).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Ungültiger Wert für {0}. Der Wert muss ein Zahlenwert größer oder gleich 1 sein.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Ungültiger Wert für {0}. Der Wert muss eine absolute HTTP- oder HTTPS-URL sein.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Die Client-ID einer benutzerzugewiesenen ManagedIdentity.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Verwaltete Identität für die Authentifizierung bei Azure Key. (veraltet)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Die Optionen „-kvm“ und „--azure-key-vault-managed-identity“ sind veraltet und sollten nicht mehr angegeben werden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Die Ressourcen-ID einer vom Benutzer zugewiesenen ManagedIdentity.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Maximale Parallelität.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Eine Datei oder ein Glob ist erforderlich.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Warnung: Die Microsoft Visual C++ 14-Runtime ist erforderlich, wurde jedoch auf ihrem System nicht erkannt.  Von „https://aka.ms/vs/17/release/vc_redist.x64.exe“ herunterladen und installieren</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Es wurden keine Eingaben zum Signieren gefunden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Ausgabedatei oder -verzeichnis. Wenn dies weggelassen wird, werden Eingabedateien überschrieben.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Herausgebername (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">CLI signieren</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Einige Dateien sind nicht vorhanden.  Versuchen Sie, einen anderen {0}-Wert oder einen vollqualifizierten Dateipfad zu verwenden.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Mandanten-ID für die Authentifizierung bei Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Digest-Algorithmus für den RFC 3161-Zeitstempelserver. Zulässige Werte sind sha256, sha384 und sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">URL für RFC 3161-Zeitstempelserver.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Der vertrauenswürdige Signaturbefehl ist veraltet. Verwenden Sie stattdessen den Artefaktsignaturbefehl.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Legt den Ausführlichkeitsgrad fest. Zulässige Werte sind \"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\" und \"trace\".</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Derzeit wird nur Windows x64 unterstützt. Weitere Informationen hinsichtlich Windows x86-Support finden Sie unter https://github.com/dotnet/sign/issues/474.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Nombre de la aplicación (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Directorio base para los archivos.  Invalida el directorio de trabajo actual.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Use el Almacén de certificados de Windows o un archivo de certificados local.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Id. de cliente para autenticarse en Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Secreto de cliente para autenticarse en Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Las opciones de secreto de cliente están obsoletas y ya no deben especificarse.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Firmar archivos binarios y contenedores.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Tipo de credencial de Azure que se usará. El valor predeterminado es DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Descripción del certificado de firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">Descripción de URL del certificado de firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algoritmo de resumen con el que se van a aplicar algoritmos hash a los archivos. Los valores permitidos son 'sha256', 'sha384', y 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Ruta de acceso al archivo que contiene las rutas de acceso de los archivos que se van a firmar o que se van a excluir de la firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Archivos para firmar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Valor no válido para {0}. El valor debe ser una ruta de acceso de directorio totalmente raíz.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Valor no válido para {0}. El valor debe ser una huella de certificado SHA-256, SHA-384 o SHA-512 (en hexadecimal).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Valor no válido para {0}. El valor debe ser 'sha256', 'sha384' o 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">La ruta de acceso del archivo no se puede rootear cuando se usa un glob. Use una ruta de acceso relativa al directorio de trabajo (o directorio base, si se usa).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Valor no válido para {0}. El valor debe ser un valor numérico mayor o igual que 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Valor no válido para {0}. El valor debe ser una dirección URL HTTP o HTTPS absoluta.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">El identificador de cliente de un ManagedIdentity asignado por el usuario.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Identidad administrada para autenticarse en Azure Key. (obsoleto)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Las opciones -kvm y --azure-key-vault-managed-identity están obsoletas y ya no deben especificarse.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">El identificador de recurso de un ManagedIdentity asignado por el usuario.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Simultaneidad máxima.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Se requiere un archivo o glob.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Advertencia: se requiere el runtime Microsoft Visual C++ 14, pero no se detectó en el sistema.  Descargar e instalar desde https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">No se encontraron entradas para firmar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Archivo o directorio de salida. Si se omite, se sobrescribirán los archivos de entrada.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Nombre del publicador (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Firma de la CLI</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Algunos archivos no existen.  Pruebe a usar otro valor {0} o una ruta de acceso de archivo completa.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Id. de inquilino para autenticarse en Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Algoritmo de resumen para el servidor de marca de tiempo RFC 3161. Los valores permitidos son sha256, sha384 y sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">Dirección URL del servidor de marca de tiempo RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">El comando trusted-signing está obsoleto. En su lugar, use el comando artifact-signing.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Establece el nivel de detalle. Los valores permitidos son \"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\" y \"trace\".</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">En este momento solo se admite Windows x64. Consulta https://github.com/dotnet/sign/issues/474 sobre la compatibilidad con Windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Nom de l’application (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Répertoire de base pour les fichiers. Remplace le répertoire de travail actuel.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Utilisez le magasin de certificats Windows ou un fichier local du certificat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID client pour l’authentification auprès d’Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Clé secrète client pour s’authentifier auprès d’Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Les options de secret du client sont obsolètes et ne doivent plus être spécifiées.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Signer les fichiers binaires et les conteneurs.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Type d’informations d’identification Azure à utiliser. Cela par défaut à DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Description du certificat de signature.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">URL de description du certificat de signature.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algorithme Digest pour hacher les fichiers avec. Les valeurs autorisées sont 'sha256', 'sha384' et 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Chemin du fichier contenant les chemins des fichiers à signer ou à exclure de la signature.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Fichier(s) à signer.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Valeur non valide pour {0}. La valeur doit être un chemin d’accès de répertoire entièrement rooté.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Valeur non valide pour {0}. La valeur doit être une empreinte digitale de certificat SHA-256, SHA-384 ou SHA-512 (en hexadécimal).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Valeur invalide pour {0}. La valeur doit être 'sha256', 'sha384' ou 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Le chemin d’accès du fichier ne peut pas être rooté lors de l’utilisation d’un glob. Utilisez un chemin d’accès relatif au répertoire de travail (ou au répertoire de base, s’il est utilisé).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Valeur non valide pour {0}. La valeur doit être une valeur numérique supérieure ou égale à 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Valeur non valide pour {0}. La valeur doit être une URL HTTP ou HTTPS absolue.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">L’ID client d’un utilisateur à qui a été attribuée ManagedIdentity.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Identité managée pour s’authentifier auprès d’Azure Key. (obsolète)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Les options -kvm et --azure-key-vault-managed-identity sont obsolètes et ne doivent plus être spécifiées.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">L’ID de ressource d’une ManagedIdentity attribuée à un utilisateur.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Concurrence maximale.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Un fichier ou un glob est requis.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Avertissement : le runtime Microsoft Visual C++ 14 est requis mais n’a pas été détecté sur votre système.  Télécharger et installer à partir de https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Aucune entrée à signer.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Fichier ou répertoire de sortie. En cas d’omission, les fichiers d’entrée sont remplacés.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Nom du serveur de publication (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Signer l’interface CLI</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Certains fichiers n’existent pas. Essayez d’utiliser une autre valeur {0} ou un chemin de fichier complet.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID du locataire pour s’authentifier auprès d’Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Algorithme de hachage pour le serveur d’horodatage RFC 3161. Les valeurs autorisées sont sha256, sha384 et sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">URL du serveur d'horodatage conforme au document RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">La commande de signature de confiance est obsolète. Utilisez plutôt la commande de signature d'artefacts.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Définit le niveau de verbosité. Les valeurs autorisées sont 'none', 'critical', 'error', 'warning', 'information', 'debug', et 'trace'</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Seul Windows x64 est pris en charge pour l’instant. Consultez https://github.com/dotnet/sign/issues/474 concernant la prise en charge de Windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Nome applicazione (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Directory di base per i file.  Esegue l'override della directory di lavoro corrente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Utilizzare l'archivio certificati di Windows o un file di certificato locale.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID client da autenticare in Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Segreto client da autenticare in Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Le opzioni del segreto client sono obsolete e non devono essere più specificate.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Consente di firmare file binari e contenitori.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Tipo di credenziale di Azure che verrà utilizzato. Verrà utilizzata l'impostazione predefinita DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Descrizione del certificato di firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">URL descrizione del certificato di firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algoritmo di digest con cui eseguire l'hashing dei file. I valori consentiti sono 'sha256', 'sha384' e 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Percorso del file contenente i percorsi dei file da firmare o escludere dalla firma.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">File da firmare.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Valore non valido per {0}. Il valore deve essere un percorso di directory completo.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Valore non valido per {0}. Il valore deve essere un’impronta digitale del certificato SHA-256, SHA-384 o SHA-512 (in formato esadecimale).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Valore non valido per {0}. Il valore deve essere 'sha256', 'sha384' o 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Il percorso del file non può avere accesso root quando si utilizza un GLOB. Usare un percorso relativo alla directory di lavoro (o alla directory di base, se usata).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Valore non valido per {0}. Il valore deve essere un numero maggiore o uguale a 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Valore non valido per {0}. Il valore deve essere un URL HTTP o HTTPS assoluto.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ID client di un elemento ManagedIdentity assegnato dall'utente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Identità gestita da autenticare in Azure Key. (obsoleto)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Le opzioni -kvm e --azure-key-vault-managed-identity sono obsolete e non devono più essere specificate.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ID risorsa di un elemento ManagedIdentity assegnato dall'utente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Concorrenza massima.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">È necessario specificare un file o un GLOB.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Avviso: il runtime di Microsoft Visual C++ 14 è obbligatorio ma non è stato rilevato nel sistema.  Scarica e installa da https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Non sono stati trovati input da firmare.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">File o directory di output. Se omessi, i file di input verranno sovrascritti.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Nome autore (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Consente di firmare l'interfaccia della riga di comando</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Alcuni file non esistono.  Provare a usare un valore di {0} diverso o un percorso di file completo.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID tenant da autenticare in Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Algoritmo di digest per il server di timestamp RFC 3161. I valori consentiti sono sha256, sha384 e sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">URL del server di timestamp RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Il comando di firma attendibile è obsoleto. Usare il comando di firma artefatti.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Imposta il livello di dettaglio. I valori consentiti sono 'none', 'critical', 'error', 'warning', 'information', 'debug' e 'trace'.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Al momento è supportato solo Windows x64. Vedere https://github.com/dotnet/sign/issues/474 sul supporto per Windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">アプリケーション名 (ClickOnce)。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">ファイルのベース ディレクトリ。 現在の作業ディレクトリをオーバーライドします。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Windows 証明書ストアまたはローカル証明書ファイルを使用します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure に対して認証するクライアント ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Azure に対して認証するクライアント シークレット。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">クライアント シークレットのオプションは廃止されているため、指定しないでください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">バイナリとコンテナーに署名します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">使用される Azure 資格情報の種類。この既定値は DefaultAzureCredential です。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">署名証明書の説明。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">署名証明書の説明 URL。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">ファイルのハッシュに使用するダイジェスト アルゴリズム。使用できる値は、'sha256'、'sha384'、および 'sha512' です。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">署名するファイルまたは署名から除外するファイルのパスを含むファイルへのパス。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">署名するファイル。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">{0} の値が無効です。値は、完全にルート化されたディレクトリ パスである必要があります。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">{0} の値が無効です。値は SHA-256、SHA-384、または SHA-512 証明書フィンガープリント (16 進数) である必要があります。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">{0} の値が無効です。値は 'sha256'、'sha384'、または 'sha512' である必要があります。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">glob を使用している場合、ファイル パスをルート化できません。作業ディレクトリへの相対パス (または使用されている場合はベース ディレクトリ) を使用してください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">{0} の値が無効です。値は、1 以上の数値である必要があります。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">{0}の値が無効です。値は HTTP または HTTPS の絶対 URL である必要があります。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ユーザー割り当て済み ManagedIdentity のクライアント ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Azure Key に対して認証するマネージド ID。(旧形式)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">-kvm オプションと --azure-key-vault-managed-identity オプションは旧形式であるため、指定しないでください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ユーザー割り当て済み ManagedIdentity のリソース ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">最大コンカレンシー。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">ファイルまたは glob が必要です。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">警告: Microsoft Visual C++ 14 ランタイムが必要ですが、システムで検出されませんでした。https://aka.ms/vs/17/release/vc_redist.x64.exe からダウンロードしてインストールしてください</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">署名する入力が見つかりません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">出力ファイルまたはディレクトリ。省略すると、入力ファイルが上書きされます。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">パブリッシャー名 (ClickOnce)。</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">CLI に署名</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">一部のファイルが存在しません。別の {0} 値または完全修飾ファイル パスを使用してみてください。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure に対して認証するテナント ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">RFC 3161 タイムスタンプ サーバーのダイジェスト アルゴリズム。使用できる値は、sha256、sha384、および sha512 です。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">RFC 3161 タイムスタンプ サーバーの URL。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">trusted-signing コマンドは廃止されています。代わりに artifact-signing コマンドを使用してください。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">詳細レベルを設定します。指定できる値は、'none'、'critical'、'error'、'warning'、'information'、'debug'、'trace' です。</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">現時点でサポートされているのは Windows x64 のみです。Windows x86 のサポートに関する https://github.com/dotnet/sign/issues/474 を参照してください。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">애플리케이션 이름(ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">파일의 기본 디렉터리입니다. 현재 작업 디렉터리를 재정의합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Windows 인증서 저장소 또는 로컬 인증서 파일을 사용합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure에 인증할 클라이언트 ID입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Azure에 인증하는 클라이언트 암호입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">클라이언트 비밀 옵션은 사용되지 않으므로 더 이상 지정하지 않아야 합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">이진 파일 및 컨테이너에 서명합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">사용할 Azure 자격 증명 형식입니다. 기본값은 DefaultAzureCredential입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">서명 인증서에 대한 설명입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">서명 인증서의 설명 URL입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">파일을 해시하는 다이제스트 알고리즘입니다. 허용되는 값은 'sha256', 'sha384' 및 'sha512'입니다.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">서명하거나 서명에서 제외할 파일의 경로가 포함된 파일 경로입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">서명할 파일입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">{0}에 대한 값이 잘못되었습니다. 값은 완전한 루트 디렉터리 경로여야 합니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">{0}의 값이 잘못되었습니다. 값은 SHA-256, SHA-384 또는 SHA-512 인증서 지문(16진수)이어야 합니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">{0}에 대한 값이 잘못되었습니다. 값은 'sha256', 'sha384' 또는 'sha512'.여야 합니다.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">glob을 사용할 때 파일 경로를 루팅할 수 없습니다. 작업 디렉터리(또는 사용되는 경우 기본 디렉터리)에 상대적인 경로를 사용하세요.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">{0}에 대한 값이 잘못되었습니다. 값은 1보다 크거나 같은 숫자 값이어야 합니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">{0}에 대한 값이 잘못되었습니다. 값은 절대 HTTP 또는 HTTPS URL이어야 합니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ManagedIdentity가 할당된 사용자의 클라이언트 ID입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Azure Key에 인증할 관리 ID입니다. (사용되지 않음)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">-kvm 및 --azure-key-vault-managed-identity 옵션은 사용되지 않으므로 더 이상 지정하지 않아야 합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">사용자가 할당한 ManagedIdentity의 리소스 ID입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">최대 동시성입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">파일 또는 글로브가 필요합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">경고: Microsoft Visual C++ 14 런타임이 필요하지만 시스템에서 검색되지 않았습니다.  https://aka.ms/vs/17/release/vc_redist.x64.exe 다운로드 및 설치</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">서명할 입력이 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">출력 파일 또는 디렉터리입니다. 생략하면 입력 파일을 덮어씁니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">게시자 이름(ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">CLI 서명</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">일부 파일이 존재하지 않습니다.  다른 {0} 값 또는 정규화된 파일 경로를 사용해 보세요.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure에 인증할 테넌트 ID입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">RFC 3161 타임스탬프 서버용 다이제스트 알고리즘입니다. 허용되는 값은 sha256, sha384 및 sha512입니다.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">RFC 3161 타임스탬프 서버 URL.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">trusted-signing 명령은 더 이상 사용되지 않습니다. 대신 artifact-signing 명령을 사용하세요.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">세부 정보 표시 수준을 설정합니다. 허용되는 값은 'none', 'critical', 'error', 'warning', 'information', 'debug' 및 'trace'입니다.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">현재 Windows x64만 지원됩니다. Windows x86 지원에 대해서는 https://github.com/dotnet/sign/issues/474를 참조하세요.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Nazwa aplikacji (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Katalog podstawowy dla plików.  Zastępuje bieżący katalog roboczy.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Użyj magazynu certyfikatów systemu Windows lub lokalnego pliku certyfikatów.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Identyfikator klienta do uwierzytelniania na platformie Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Klucz tajny klienta do uwierzytelniania na platformie Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Opcje klucza tajnego klienta są przestarzałe i nie należy ich już określać.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Podpisz pliki binarne i kontenery.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Typ poświadczeń platformy Azure, który będzie używany. Wartość domyślna to DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Opis certyfikatu podpisywania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">Adres URL opisu certyfikatu podpisywania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algorytm skrótu, za pomocą którego jest tworzony skrót plików. Dozwolonymi wartościami są: „sha256”, „sha384”, lub „sha512”.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Ścieżka do pliku zawierającego ścieżki plików do podpisania lub wykluczenia z podpisywania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Pliki do podpisania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Nieprawidłowa wartość dla {0}. Wartość musi być w pełni główną ścieżką katalogu.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Nieprawidłowa wartość dla algorytmu {0}. Wartość musi być odciskiem palca certyfikatu z algorytmem SHA-256, SHA-384 lub SHA-512 (w formacie szesnastkowym).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Nieprawidłowa wartość dla {0}. Wartością musi być „sha256”, „sha384”, lub „sha512”.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Ścieżka pliku nie może być z dostępem do konta root, gdy jest używany element globalny. Użyj ścieżki odnoszącej się do katalogu roboczego (lub katalogu podstawowego, jeśli jest używany).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Nieprawidłowa wartość dla {0}. Wartość musi być większa lub równa 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Nieprawidłowa wartość dla {0}. Wartość musi być bezwzględnym adresem URL protokołu HTTP lub HTTPS.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Identyfikator klienta elementu ManagedIdentity przypisanego przez użytkownika.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Tożsamość zarządzana do uwierzytelnienia w usłudze Azure Key. (przestarzały)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Opcje -kvm i --azure-key-vault-managed-identity są przestarzałe i nie należy ich już określać.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Identyfikator zasobu elementu ManagedIdentity przypisanego przez użytkownika.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Maksymalna współbieżność.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Wymagany jest plik lub element globalny.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Ostrzeżenie: środowisko uruchomieniowe Microsoft Visual C++ 14 jest wymagane, ale nie zostało wykryte w systemie.  Pobierz i zainstaluj z witryny https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Nie znaleziono danych wejściowych do podpisania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Plik wyjściowy lub katalog. W przypadku pominięcia pliki wejściowe zostaną zastąpione.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Nazwa wydawcy (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Interfejs wiersza polecenia podpisywania</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Niektóre pliki nie istnieją.  Spróbuj użyć innej wartości {0} lub w pełni kwalifikowanej ścieżki pliku.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Identyfikator dzierżawy na potrzeby uwierzytelniania na platformie Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Algorytm skrótu dla serwera znacznika czasu RFC 3161. Dozwolonymi wartościami są: sha256, sha384 i sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">Adres URL serwera znacznika czasu RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Polecenie zaufanego podpisywania jest przestarzałe. Zamiast tego użyj polecenia podpisywania artefaktu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Ustawia poziom szczegółowości. Dozwolone wartości to „none”, „critical”, „error”, „warning”, „information”, „debug” i „trace”.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Obecnie obsługiwany jest tylko system Windows x64. Zobacz stronę https://github.com/dotnet/sign/issues/474 odnośnie pomocy technicznej systemu Windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Nome do aplicativo (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Diretório base para arquivos.  Substitui o diretório de trabalho atual.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Use o Repositório de Certificados do Windows ou um arquivo de certificado local.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID do cliente a ser autenticada no Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Segredo do cliente a ser autenticado no Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">As opções de segredo do cliente são obsoletas e não devem mais ser especificadas.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Autenticar contêineres e binários.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Tipo de credencial do Azure que será usada. O padrão é DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Descrição do certificado de autenticação.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">URL de descrição do certificado de autenticação.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Algoritmo de código hash para arquivos de hash. Os valores permitidos são 'sha256', 'sha384' e 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Caminho para o arquivo que contém os caminhos dos arquivos a serem assinados ou excluídos da assinatura.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Arquivo(s) para autenticar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Valor inválido para {0}. O valor deve ser um caminho de diretório totalmente desbloqueado por rooting.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Valor inválido para {0}. O valor deve ser uma impressão digital de certificado SHA-256, SHA-384 ou SHA-512 (em hexadecimal).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Valor inválido para {0}. O valor deve ser 'sha256', 'sha384' ou 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">O caminho do arquivo não pode estar desbloqueado por rooting ao usar um glob. Use um caminho relativo ao diretório de trabalho (ou diretório base, se usado).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Valor inválido para {0}. O valor deve ser um valor numérico maior ou igual a 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Valor inválido para {0}. O valor deve ser uma URL HTTP ou HTTPS absoluta.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">A ID do cliente de um ManagedIdentity atribuído pelo usuário.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Identidade gerenciada a ser autenticada na Chave do Azure Key. (obsoleta)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">As opções -kvm e --azure-key-vault-managed-identity são obsoletas e não devem mais ser especificadas.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">A ID de recurso de um ManagedIdentity atribuído pelo usuário.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Simultaneidade máxima.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">É necessário um arquivo ou um glob.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Aviso: o runtime do Microsoft Visual C++ 14 é necessário, mas não foi detectado no sistema.  Baixar e instalar de https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Nenhuma entrada encontrada para autenticar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Arquivo ou diretório de saída. Se omitido, os arquivos de entrada serão substituídos.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Nome do editor (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Autenticar CLI</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Alguns arquivos não existem.  Tente usar um valor diferente de {0} ou um caminho de arquivo totalmente qualificado.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">ID do locatário a ser autenticada no Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Resumo do algoritmo para o servidor de carimbo de data/hora RFC 3161. Os valores permitidos são sha256, sha384 e sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">URL do servidor de carimbo de data/hora do RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">O comando de assinatura confiável está obsoleto. Em vez disso, use o comando de assinatura de artefato.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Define o nível de detalhamento. Os valores permitidos são 'none', 'critical', 'error', 'warning', 'information', 'debug' e 'trace'.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">No momento, somente o Windows x64 é compatível. Consulte https://github.com/dotnet/sign/issues/474 para obter suporte com o Windows x86.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Имя приложения (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Базовый каталог для файлов.  Переопределяет текущий рабочий каталог.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Используйте хранилище сертификатов Windows или локальный файл сертификата.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">ИД клиента для проверки подлинности в Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Секрет клиента для проверки подлинности в Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Параметры секрета клиента устарели и больше не должны указываться.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">Подписывание двоичных файлов и контейнеров.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Тип учетных данных Azure, который будет использоваться. По умолчанию: DefaultAzureCredential.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">Описание сертификата для подписи</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">Описание URL-адреса сертификата для подписи</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Алгоритм дайджеста для хэширования файлов. Допустимые значения: \"sha256\", \"sha384\" и \"sha512\".</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">Путь к файлу, содержащему пути к файлам, которые нужно подписать или исключить из подписания.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">Файлы для подписи.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">Недопустимое значение для {0}. Значение должно быть полным корневым путем к каталогу.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">Недопустимое значение для {0}. Значение должно быть отпечатком сертификата SHA-256, SHA-384 или SHA-512 (в шестнадцатеричном формате).</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">Недопустимое значение для {0}. Необходимо использовать \"sha256\", \"sha384\" или \"sha512\".</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Путь к файлу не может быть корневым при использовании стандартной маски. Используйте путь относительно рабочего каталога (или базового каталога, если он используется).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">Недопустимое значение для \"{0}\". Значение должно быть числом, большим или равным 1.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">Недопустимое значение для {0}. Значение должно быть абсолютным URL-адресом HTTP или HTTPS.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Идентификатор клиента для управляемого удостоверения, назначаемого пользователем.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Управляемое удостоверение для проверки подлинности в Azure Key. (устарело)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Параметры -kvm и --azure-key-vault-managed-identity устарели и больше не должны указываться.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">ИД ресурса для управляемого удостоверения, назначаемого пользователем.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Максимальный параллелизм.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Требуется файл или стандартная маска.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Внимание! Среда выполнения Microsoft Visual C++ 14 является обязательной, но не обнаружена в вашей системе.  Скачайте и установите ее: https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">Не найдены входящие данные для подписи.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Выходной файл или каталог. Если этот параметр опущен, входные файлы будут перезаписаны.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Имя издателя (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">Подписывание CLI</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Некоторые файлы не существуют.  Попробуйте использовать другое значение {0} или полный путь к файлу.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">ИД клиента для проверки подлинности в Azure.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">Алгоритм дайджеста для сервера меток времени RFC 3161. Допустимые значения: sha256, sha384 и sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">URL-адрес сервера меток времени RFC 3161.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Команда доверенного подписания устарела. Вместо нее применяйте команду подписания артефактов.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Задает уровень детализации. Допустимые значения: \"none\" (нет), \"critical\" (критическое), \"error\" (ошибки), \"warning\" (предупреждения), \"information\" (информация), \"debug\" (отладка) и \"trace\" (трассировка).</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Сейчас поддерживается только Windows x64. Сведения о поддержке Windows x86 см. на странице https://github.com/dotnet/sign/issues/474.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">Uygulama adı (ClickOnce).</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">Dosyalar için temel dizin. Geçerli çalışma dizinini geçersiz kılar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">Windows Sertifika Deposu veya yerel bir sertifika dosyası kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure için kimlik doğrulamak amacıyla kullanılan istemci kimliği.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">Azure için kimlik doğrulamak amacıyla kullanılan gizli anahtar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">Gizli anahtar seçenekleri kullanımdan kaldırıldı ve artık belirtilmemelidir.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">İkili dosyaları ve kapsayıcıları imzalayın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">Kullanılacak Azure kimlik bilgisi türü. Bu varsayılan DefaultAzureCredential değerine ayarlanır.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">İmzalama sertifikasının açıklaması.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">İmzalama sertifikasının açıklama URL’si.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">Dosyaların karmasını oluşturmak için kullanılan karma algoritması. İzin verilen değerler şunlardır: 'sha256', 'sha384' ve 'sha512'.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">İmzalanacak veya imzalamadan dışlanacak dosyaların yollarını içeren dosya yolu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">İmzalanacak dosyalar.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">{0} için geçersiz değer. Değer, tam olarak kök erişim izni verilmiş bir dizin yolu olmalıdır.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">{0} için geçersiz değer. Değer bir SHA-256, SHA-384 veya SHA-512 sertifikası parmak izi (onaltılı olarak) olmalıdır.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">{0} için geçersiz değer. Değer 'sha256', 'sha384' veya 'sha512' olmalıdır.</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">Glob kullanılırken dosya yoluna kök erişim izni verilemez. Çalışma diziniyle (veya kullanılıyorsa, temel dizinle) ilişkili bir yol kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">{0} için geçersiz değer. Değer, 1’den büyük veya buna eşit bir sayı değeri olmalıdır.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">{0} için geçersiz değer. Değer mutlak bir HTTP veya HTTPS URL’si olmalıdır.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Kullanıcı tarafından atanan yönetilen kimliğin istemci kimliği.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">Azure Key Vault için kimlik doğrulamak amacıyla kullanılan yönetilen kimlik. (kullanımdan kaldırıldı)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">-kvm ve --azure-key-vault-managed-identity seçenekleri kullanımdan kaldırıldı ve artık belirtilmemelidir.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">Kullanıcı tarafından atanan yönetilen kimliğin kaynak kimliği.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">Maksimum eşzamanlılık.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">Dosya veya glob gerekiyor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">Uyarı: Microsoft Visual C++ 14 çalışma zamanı gerekiyor ancak sisteminiz üzerinde algılanmadı.  İndirme ve yükleme için https://aka.ms/vs/17/release/vc_redist.x64.exe</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">İmzalanacak giriş dosyası yok.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">Çıkış dosyası veya dizini. Atlanırsa, giriş dosyalarının üzerine yazılır.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">Yayımcı adı (ClickOnce).</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">CLI’yı imzala</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">Bazı dosyalar mevcut değil. Farklı bir {0} değeri veya tam bir dosya yolu kullanmayı deneyin.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">Azure için kimlik doğrulamak amacıyla kullanılan kiracı kimliği.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">RFC 3161 zaman damgası sunucusu için karma algoritması. İzin verilen değerler şunlardır. sha256, sha384 ve sha512.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">RFC 3161 zaman damgası sunucusu URL’si.</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">Güvenilen imzalama komutu artık kullanılmıyor. Bunun yerine yapıt imzalama komutunu kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">Ayrıntı düzeyini ayarlar. İzin verilen değerler: 'none', 'critical', 'error', 'warning', 'information', 'debug' ve 'trace'.</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">Şu anda yalnızca Windows x64 destekleniyor. Windows x86 desteği için https://github.com/dotnet/sign/issues/474 sayfasına bakın.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">应用程序名称(ClickOnce)。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">文件的基目录。替代当前工作目录。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">使用 Windows 证书存储或本地证书文件。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 进行身份验证的客户端 ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 进行身份验证的客户端密码。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">客户端密码选项已过时，不应再指定。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">对二进制文件和容器进行签名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">将使用的 Azure 凭据类型。此项默认为 DefaultAzureCredential。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">签名证书的说明。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">签名证书的说明 URL。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">用于对文件进行哈希处理的摘要算法。允许的值为 \"sha256\"、\"sha384\" 和 \"sha512\"。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">包含要签名或从签名中排除的文件路径的文件的路径。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">要签名的文件。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">{0} 的值无效。该值必须是完整的根目录路径。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">{0} 的值无效。该值必须是 SHA-256、SHA-384 或 SHA-512 证书指纹(十六进制)。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">{0} 的值无效。值必须为 \"sha256\"、\"sha384\" 或 \"sha512\"。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">使用 glob 时，文件路径不能为根路径。请使用相对于工作目录(或基目录，如果使用)的路径。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">{0} 的值无效。该值必须是大于或等于 1 的数值。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">{0} 的值无效。值必须是绝对 HTTP 或 HTTPS URL。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">用户分配的 ManagedIdentity 的客户端 ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">要向 Azure Key 进行身份验证的托管标识。(已过时)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">-kvm 和 --azure-key-vault-managed-identity 选项已过时，不应再指定。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">用户分配的 ManagedIdentity 的资源 ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">最大并发。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">文件或 glob 是必需的。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">警告: Microsoft Visual C++ 14 运行时是必需项，但在系统上未检测到。从 https://aka.ms/vs/17/release/vc_redist.x64.exe 下载并安装</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">找不到要签名的输入。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">输出文件或目录。如果省略，则输入文件将被覆盖。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">发布服务器名称(ClickOnce)。</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">对 CLI 进行签名</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">某些文件不存在。请尝试使用其他 {0} 值或完全限定的文件路径。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 进行身份验证的租户 ID。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">RFC 3161 时间戳服务器的摘要算法。允许的值为 sha256、sha384 和 sha512。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">RFC 3161 时间戳服务器 URL。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">受信任签名命令已过时。请改用工件签名命令。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">设置详细级别。允许的值为 \"none\"、\"critical\"、\"error\"、\"warning\"、\"information\"、\"debug\" 和 \"trace\"。</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">目前仅支持 Windows x64。有关 Windows x86 支持，请参阅 https://github.com/dotnet/sign/issues/474。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/Resources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ApplicationNameOptionDescription\">\n        <source>Application name (ClickOnce).</source>\n        <target state=\"translated\">應用程式名稱 (ClickOnce)。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"BaseDirectoryOptionDescription\">\n        <source>Base directory for files.  Overrides the current working directory.</source>\n        <target state=\"translated\">檔案的基底目錄。覆寫目前的工作目錄。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateStoreCommandDescription\">\n        <source>Use Windows Certificate Store or a local certificate file.</source>\n        <target state=\"translated\">使用 Windows 憑證存放區或本機憑證檔案。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientIdOptionDescription\">\n        <source>Client ID to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 進行驗證的用戶端識別碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionDescription\">\n        <source>Client secret to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 進行驗證的用戶端密碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ClientSecretOptionsObsolete\">\n        <source>The client secret options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">用戶端密碼選項已過時，應不再指定。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CodeCommandDescription\">\n        <source>Sign binaries and containers.</source>\n        <target state=\"translated\">簽署二進位檔和容器。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CredentialTypeOptionDescription\">\n        <source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>\n        <target state=\"translated\">將使用的 Azure 認證類型。這會預設為 DefaultAzureCredential。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionOptionDescription\">\n        <source>Description of the signing certificate.</source>\n        <target state=\"translated\">簽署憑證的描述。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"DescriptionUrlOptionDescription\">\n        <source>Description URL of the signing certificate.</source>\n        <target state=\"translated\">簽署憑證的描述 URL。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FileDigestOptionDescription\">\n        <source>Digest algorithm to hash files with. Allowed values are 'sha256', 'sha384', and 'sha512'.</source>\n        <target state=\"translated\">用於雜湊檔案的摘要演算法。允許的值為 'sha256'、'sha384' 和 'sha512'。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"FileListOptionDescription\">\n        <source>Path to file containing paths of files to sign or to exclude from signing.</source>\n        <target state=\"translated\">包含要簽署或從簽署排除之檔案路徑的檔案路徑。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FilesArgumentDescription\">\n        <source>File(s) to sign.</source>\n        <target state=\"translated\">要簽署的檔案。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidBaseDirectoryValue\">\n        <source>Invalid value for {0}. The value must be a fully rooted directory path.</source>\n        <target state=\"translated\">{0} 的值無效。值必須是完整的根目錄路徑。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidCertificateFingerprintValue\">\n        <source>Invalid value for {0}. The value must be a SHA-256, SHA-384, or SHA-512 certificate fingerprint (in hexadecimal).</source>\n        <target state=\"translated\">{0} 的值無效。該值必須是 SHA-256、SHA-384 或 SHA-512 憑證指紋 (十六進位格式)。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the option name (e.g.:  --certificate-fingerprint).  {Locked=\"SHA-256\", \"SHA-384\", \"SHA-512\"} are cryptographic hash algorithms.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidDigestValue\">\n        <source>Invalid value for {0}. The value must be 'sha256', 'sha384', or 'sha512'.</source>\n        <target state=\"translated\">{0} 的值無效。值必須是 'sha256'、'sha384' 或 'sha512'。</target>\n        <note>{Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names and should not be localized.  {NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --file-digest) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidFileValue\">\n        <source>The file path cannot be rooted when using a glob. Use a path relative to the working directory (or base directory, if used).</source>\n        <target state=\"translated\">使用 Glob 時，檔案路徑不可為根目錄。請使用工作目錄或基底目錄 (若使用該目錄) 的相對路徑。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"InvalidHttpsUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTPS URL.</source>\n        <target state=\"new\">Invalid value for {0}. The value must be an absolute HTTPS URL.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --artifact-signing-endpoint) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidMaxConcurrencyValue\">\n        <source>Invalid value for {0}. The value must be a number value greater than or equal to 1.</source>\n        <target state=\"translated\">{0} 的值無效。值必須是大或等於 1 的數值。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --max-concurrency) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"InvalidUrlValue\">\n        <source>Invalid value for {0}. The value must be an absolute HTTP or HTTPS URL.</source>\n        <target state=\"translated\">{0} 的值無效。值必須是絕對 HTTP 或 HTTPS URL。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --timestamp-url) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityClientIdOptionDescription\">\n        <source>The client id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">使用者指派 ManagedIdentity 的用戶端識別碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionDescription\">\n        <source>Managed identity to authenticate to Azure Key. (obsolete)</source>\n        <target state=\"translated\">要向 Azure Key 進行驗證的受控識別。(已過時)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityOptionObsolete\">\n        <source>The -kvm and --azure-key-vault-managed-identity options are obsolete and should no longer be specified.</source>\n        <target state=\"translated\">-kvm 和 --azure-key-vault-managed-identity 選項已過時，不應再指定。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ManagedIdentityResourceIdOptionDescription\">\n        <source>The resource id of a user assigned ManagedIdentity.</source>\n        <target state=\"translated\">使用者指派 ManagedIdentity 的資源識別碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MaxConcurrencyOptionDescription\">\n        <source>Maximum concurrency.</source>\n        <target state=\"translated\">並行最大值。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MissingFileValue\">\n        <source>A file or glob is required.</source>\n        <target state=\"translated\">需要檔案或 Glob。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"MsvcrtNotDetected\">\n        <source>Warning:  The Microsoft Visual C++ 14 runtime is required but was not detected on your system.  Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</source>\n        <target state=\"translated\">警告: 需要 Microsoft Visual C++ 14 執行階段，但在您的系統上偵測不到。從 https://aka.ms/vs/17/release/vc_redist.x64.exe 下載並安裝</target>\n        <note>{Locked=\"https://aka.ms/vs/17/release/vc_redist.x64.exe\"} is a URL.</note>\n      </trans-unit>\n      <trans-unit id=\"NoFilesToSign\">\n        <source>No inputs found to sign.</source>\n        <target state=\"translated\">找不到要簽署的輸入。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OutputOptionDescription\">\n        <source>Output file or directory. If omitted, input files will be overwritten.</source>\n        <target state=\"translated\">輸出檔案或目錄。如果省略，則會覆寫輸入檔案。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"PublisherNameOptionDescription\">\n        <source>Publisher name (ClickOnce).</source>\n        <target state=\"translated\">發行者名稱 (ClickOnce)。</target>\n        <note>ClickOnce is a Microsoft deployment technology.</note>\n      </trans-unit>\n      <trans-unit id=\"SignCommandDescription\">\n        <source>Sign CLI</source>\n        <target state=\"translated\">簽署 CLI</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SomeFilesDoNotExist\">\n        <source>Some files do not exist.  Try using a different {0} value or a fully qualified file path.</source>\n        <target state=\"translated\">某些檔案不存在。請嘗試使用不同的 {0} 值或完整檔案路徑。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is an option name (e.g.:  --base-directory) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TenantIdOptionDescription\">\n        <source>Tenant ID to authenticate to Azure.</source>\n        <target state=\"translated\">要向 Azure 進行驗證的租用戶識別碼。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"TimestampDigestOptionDescription\">\n        <source>Digest algorithm for the RFC 3161 timestamp server. Allowed values are sha256, sha384, and sha512.</source>\n        <target state=\"translated\">RFC 3161 時間戳記伺服器的摘要演算法。允許的值為 sha256、sha384 和 sha512。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161), and {Locked=\"sha256\", \"sha384\", \"sha512\"} are cryptographic hash algorithm names should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TimestampUrlOptionDescription\">\n        <source>RFC 3161 timestamp server URL.</source>\n        <target state=\"translated\">RFC 3161 時間戳記伺服器 URL。</target>\n        <note>{Locked=\"RFC 3161\"} is an Internet standard (https://www.rfc-editor.org/info/rfc3161) and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"TrustedSigningCommandObsolete\">\n        <source>The trusted-signing command is obsolete. Use the artifact-signing command instead.</source>\n        <target state=\"translated\">信任簽署命令已過時。請改為使用成品簽署命令。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VerbosityOptionDescription\">\n        <source>Sets the verbosity level. Allowed values are 'none', 'critical', 'error', 'warning', 'information', 'debug', and 'trace'.</source>\n        <target state=\"translated\">設定詳細資訊層級。允許的值為 'none'、'critical'、'error'、'warning'、'information'、'debug' 和 'trace'。</target>\n        <note>{Locked=\"none\", \"critical\", \"error\", \"warning\", \"information\", \"debug\", \"trace\"} are option values and should not be localized.</note>\n      </trans-unit>\n      <trans-unit id=\"x86NotSupported\">\n        <source>Only Windows x64 is supported at this time. See https://github.com/dotnet/sign/issues/474 regarding Windows x86 support.</source>\n        <target state=\"translated\">目前只支援 Windows x64。如需 Windows x86 支援，請參閱 https://github.com/dotnet/sign/issues/474 (英文)。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Název účtu pro důvěryhodné podepisování</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Název profilu certifikátu</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Použijte důvěryhodné podepisování. (zastaralé, místo toho použít artifact-signing)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Koncový bod důvěryhodného podpisového účtu Hodnota musí být identifikátor URI, který odpovídá oblasti, ve které jste vytvořili důvěryhodný podpisový účet a profil certifikátu.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Der Kontoname der vertrauensvollen Signatur.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Der Zertifikatprofilname.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Verwenden Sie die vertrauenswürdige Signatur. (veraltet, stattdessen Artefaktsignierung verwenden)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Der Endpunkt des Kontos der vertrauensvollen Signatur. Der Wert muss ein URI sein, der der Region entspricht, in der Ihr Konto der vertrauensvollen Signatur und das Zertifikatprofil erstellt wurden.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Nombre de la cuenta de firma de confianza.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nombre del perfil de certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Use la firma de confianza. (obsoleto, use la firma de artefactos en su lugar)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Punto de conexión de la cuenta de firma de confianza. El valor debe ser un identificador URI que se alinee con la región en la que se han creado la cuenta de firma de confianza y el perfil de certificado.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Nom de compte Signatures de confiance.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nom du profil de certificat.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Utilisez le service Signatures de confiance. (obsolète, utilisez plutôt la signature d’artefact)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Point de terminaison du compte Signatures de confiance. La valeur doit être un URI qui s’aligne sur la région dans laquelle votre compte Signatures de confiance et votre profil de certificat ont été créés.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Nome dell'account di firma attendibile.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nome profilo certificato.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Usare Firma attendibile. (obsoleto, usare la firma artefatti)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Endpoint dell'account di firma attendibile. Il valore deve essere un URI allineato all'area in cui sono stati creati l'account di firma attendibile e il profilo certificato.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">信頼された署名のアカウント名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">証明書プロファイル名。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">信頼された署名を使用します。(廃止されています。代わりに artifact-signing を使用してください)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">信頼された署名アカウントのエンドポイント。値は、信頼された署名アカウントと証明書プロファイルが作成されたリージョンに合った URI である必要があります。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">신뢰할 수 있는 서명 계정 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">인증서 프로필 이름입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">신뢰할 수 있는 서명을 사용합니다. (사용되지 않음, 대신 아티팩트 서명 사용)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">신뢰할 수 있는 서명 계정 엔드포인트입니다. 값은 신뢰할 수 있는 서명 계정 및 인증서 프로필이 생성된 지역에 맞는 URI여야 합니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Nazwa konta usługi Zaufane podpisywanie.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Nazwa profilu certyfikatu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Użyj usługi Zaufane podpisywanie. (przestarzałe, zamiast tego użyj rozwiązania Artifact Signing)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Punkt końcowy konta usługi Zaufane podpisywanie. Wartość musi być identyfikatorem URI, który jest zgodny z regionem, w ramach którego utworzono konto usługi Zaufane podpisywanie i profil certyfikatu.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">O nome da Conta de Assinatura Confiável.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">O nome do Perfil de Certificado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Use a Assinatura Confiável. (obsoleto, use a assinatura de artefatos)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">O ponto de extremidade da Conta de Assinatura Confiável. O valor deve ser uma URI que se alinhe à região em que sua Conta de Assinatura Confiável e o Perfil de Certificado foram criados.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Имя учетной записи для доверенного подписания.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Имя профиля сертификата.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Используйте доверенное подписание. (устарело, вместо этого применяйте подписание артефактов)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Конечная точка учетной записи для доверенного подписания. Значением должен быть URI, соответствующий региону, в котором созданы учетная запись для доверенного подписания и профиль сертификата.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">Güvenilir İmzalama Hesabı adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">Sertifika Profili adı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">Güvenilen İmzalama hizmetini kullanın. (artık kullanılmıyor, bunun yerine yapıt imzalama kullanın)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">Güvenilir İmzalama Hesabı uç noktası. De, Güvenilir İmzalama Hesabınızın ve Sertifika Profilinin oluşturulduğu bölgeyle uyumlu bir URI olmalıdır.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">受信任签名帐户名称。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">证书配置文件名称。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">使用受信任签名。(已过时，请改用工件签名)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">受信任签名帐户终结点。该值必须是与创建受信任签名帐户和证书配置文件的区域相对应的 URI。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Cli/xlf/TrustedSigningResources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../TrustedSigningResources.resx\">\n    <body>\n      <trans-unit id=\"AccountOptionDescription\">\n        <source>The Trusted Signing Account name.</source>\n        <target state=\"translated\">信任簽署帳戶名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateProfileOptionDescription\">\n        <source>The Certificate Profile name.</source>\n        <target state=\"translated\">憑證設定檔名稱。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CommandDescription\">\n        <source>Use Trusted Signing. (obsolete, use artifact-signing instead)</source>\n        <target state=\"translated\">使用信任簽署。(已過時，請改用成品簽署)</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"EndpointOptionDescription\">\n        <source>The Trusted Signing Account endpoint. The value must be a URI that aligns to the region that your Trusted Signing Account and Certificate Profile were created in.</source>\n        <target state=\"translated\">信任簽署帳戶端點。值必須是 URI，且與您的信任簽署帳戶和憑證設定檔建立區域一致。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/AppInitializer.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class AppInitializer\n    {\n        internal static void Initialize()\n        {\n            AppRootDirectoryLocator locator = new();\n            DirectoryInfo appRootDirectory = locator.Directory;\n\n            string baseDirectory = Path.Combine(appRootDirectory.FullName, \"tools\", \"SDK\", \"x64\");\n\n            //\n            // Ensure we invoke wintrust!DllMain before we get too far.\n            // This will call wintrust!RegisterSipsFromIniFile and read in wintrust.dll.ini\n            // to swap out some local SIPs. Internally, wintrust will call LoadLibraryW\n            // on each DLL= entry, so we need to also adjust our DLL search path or we'll\n            // load unwanted system-provided copies.\n            //\n            Kernel32.SetDllDirectoryW(baseDirectory);\n            Kernel32.LoadLibraryW(Path.Combine(baseDirectory, \"wintrust.dll\"));\n            Kernel32.LoadLibraryW(Path.Combine(baseDirectory, \"mssign32.dll\"));\n\n            // This is here because we need to P/Invoke into clr.dll for _AxlPublicKeyBlobToPublicKeyToken.\n            string windir = Environment.GetEnvironmentVariable(\"windir\")!;\n            string netfxDir = Path.Combine(windir, \"Microsoft.NET\", \"Framework64\", \"v4.0.30319\");\n\n            AddEnvironmentPath(netfxDir);\n        }\n\n        private static void AddEnvironmentPath(string path)\n        {\n            const string name = \"PATH\";\n\n            string paths = Environment.GetEnvironmentVariable(name) ?? string.Empty;\n            string newPaths = string.Join(Path.PathSeparator, paths, path);\n\n            Environment.SetEnvironmentVariable(name, newPaths);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Certificates/CertificateVerifier.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class CertificateVerifier : ICertificateVerifier\n    {\n        private readonly ILogger<ICertificateVerifier> _logger;\n\n        // Dependency injection requires a public constructor.\n        public CertificateVerifier(ILogger<ICertificateVerifier> logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _logger = logger;\n        }\n\n        public void Verify(X509Certificate2 certificate)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            DateTime now = DateTime.Now;\n\n            if (now < certificate.NotBefore)\n            {\n                // See https://github.com/dotnet/roslyn-analyzers/issues/5626\n#pragma warning disable CA2254 // Template should be a static expression\n                _logger.LogError(Resources.CertificateIsNotYetTimeValid);\n                throw new SigningException(Resources.CertificateIsNotYetTimeValid);\n            }\n            else if (certificate.NotAfter < now)\n            {\n                _logger.LogError(Resources.CertificateIsExpired);\n                throw new SigningException(Resources.CertificateIsExpired);\n#pragma warning restore CA2254 // Template should be a static expression\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Certificates/ICertificateVerifier.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    internal interface ICertificateVerifier\n    {\n        void Verify(X509Certificate2 certificate);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/AppxBundleContainer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Xml.Linq;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class AppxBundleContainer : Container\n    {\n        private readonly FileInfo _appxBundle;\n        private string? _bundleVersion;\n        private readonly IDirectoryService _directoryService;\n        private readonly ILogger _logger;\n        private readonly IMakeAppxCli _makeAppxCli;\n\n        public AppxBundleContainer(\n            FileInfo appxBundle,\n            IDirectoryService directoryService,\n            IFileMatcher fileMatcher,\n            IMakeAppxCli makeAppxCli,\n            ILogger logger)\n            : base(fileMatcher)\n        {\n            ArgumentNullException.ThrowIfNull(appxBundle, nameof(appxBundle));\n            ArgumentNullException.ThrowIfNull(directoryService, nameof(directoryService));\n            ArgumentNullException.ThrowIfNull(makeAppxCli, nameof(makeAppxCli));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _appxBundle = appxBundle;\n            _directoryService = directoryService;\n            _makeAppxCli = makeAppxCli;\n            _logger = logger;\n        }\n\n        public override async ValueTask OpenAsync()\n        {\n            if (TemporaryDirectory is not null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            TemporaryDirectory = new TemporaryDirectory(_directoryService);\n\n            var args = $@\"unbundle /p \"\"{_appxBundle.FullName}\"\" /d \"\"{TemporaryDirectory!.Directory.FullName}\"\" /o\";\n\n            await _makeAppxCli.RunAsync(args);\n\n            _bundleVersion = GetBundleVersion();\n        }\n\n        public override async ValueTask SaveAsync()\n        {\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo newAppxBundle = new(Path.Combine(temporaryDirectory.Directory.FullName, _appxBundle.Name));\n\n                var args = $@\"bundle /d \"\"{TemporaryDirectory.Directory.FullName}\"\" /p \"\"{newAppxBundle.FullName}\"\" /bv {_bundleVersion} /o\";\n\n                await _makeAppxCli.RunAsync(args);\n\n                _appxBundle.Delete();\n\n                File.Move(newAppxBundle.FullName, _appxBundle.FullName, overwrite: true);\n\n                _appxBundle.Refresh();\n            }\n        }\n\n        private string? GetBundleVersion()\n        {\n            string fileName = Path.Combine(TemporaryDirectory!.Directory.FullName, \"AppxMetadata\", \"AppxBundleManifest.xml\");\n\n            using (FileStream stream = File.OpenRead(fileName))\n            {\n                XDocument manifest = XDocument.Load(stream, LoadOptions.PreserveWhitespace);\n                XNamespace ns = \"http://schemas.microsoft.com/appx/2013/bundle\";\n\n                return manifest.Root?.Element(ns + \"Identity\")?.Attribute(\"Version\")?.Value;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/AppxContainer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\nusing System.Xml.Linq;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    // Unpacking and repacking an appx will strip it of its signature\n    // We can also update the publisher of the appxmanifest\n    internal sealed class AppxContainer : Container\n    {\n        private readonly FileInfo _appx;\n        private readonly IDirectoryService _directoryService;\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ILogger _logger;\n        private readonly IMakeAppxCli _makeAppxCli;\n\n        public AppxContainer(\n            FileInfo appx,\n            ICertificateProvider certificateProvider,\n            IDirectoryService directoryService,\n            IFileMatcher fileMatcher,\n            IMakeAppxCli makeAppxCli,\n            ILogger logger)\n            : base(fileMatcher)\n        {\n            ArgumentNullException.ThrowIfNull(appx, nameof(appx));\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(directoryService, nameof(directoryService));\n            ArgumentNullException.ThrowIfNull(makeAppxCli, nameof(makeAppxCli));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _appx = appx;\n            _directoryService = directoryService;\n            _certificateProvider = certificateProvider;\n            _makeAppxCli = makeAppxCli;\n            _logger = logger;\n        }\n\n        public override async ValueTask OpenAsync()\n        {\n            if (TemporaryDirectory is not null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            TemporaryDirectory = new TemporaryDirectory(_directoryService);\n\n            _logger.LogInformation(\n                Resources.OpeningContainer,\n                _appx.FullName,\n                TemporaryDirectory.Directory.FullName);\n\n            var args = $@\"unpack /p \"\"{_appx.FullName}\"\" /d \"\"{TemporaryDirectory!.Directory.FullName}\"\" /l /o\";\n\n            await _makeAppxCli.RunAsync(args);\n\n            await UpdateManifestPublisherAsync();\n        }\n\n        public override async ValueTask SaveAsync()\n        {\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo newAppx = new(Path.Combine(temporaryDirectory.Directory.FullName, _appx.Name));\n\n                var args = $@\"pack /d \"\"{TemporaryDirectory!.Directory.FullName}\"\" /p \"\"{newAppx.FullName}\"\" /o /l\";\n\n                await _makeAppxCli.RunAsync(args);\n\n                _appx.Delete();\n\n                File.Move(newAppx.FullName, _appx.FullName, overwrite: true);\n\n                _appx.Refresh();\n            }\n        }\n\n        private async Task UpdateManifestPublisherAsync()\n        {\n            FileInfo appxManifest = new(Path.Combine(TemporaryDirectory!.Directory.FullName, \"AppxManifest.xml\"));\n            XDocument manifest;\n\n            using (FileStream stream = appxManifest.OpenRead())\n            {\n                manifest = XDocument.Load(stream, LoadOptions.PreserveWhitespace);\n                XNamespace ns = \"http://schemas.microsoft.com/appx/manifest/foundation/windows10\";\n\n                XElement? idElement = manifest.Root?.Element(ns + \"Identity\");\n\n                if (idElement is not null)\n                {\n                    using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync())\n                    {\n                        string publisher = certificate.SubjectName.Name;\n\n                        idElement.SetAttributeValue(\"Publisher\", publisher);\n                    }\n                }\n            }\n\n            using (FileStream stream = appxManifest.Open(FileMode.Create, FileAccess.Write, FileShare.None))\n            {\n                manifest.Save(stream);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/Container.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\n\nnamespace Sign.Core\n{\n    internal abstract class Container : IContainer\n    {\n        private readonly IFileMatcher _fileMatcher;\n\n        protected TemporaryDirectory? TemporaryDirectory { get; set; }\n\n        protected Container(IFileMatcher fileMatcher)\n        {\n            ArgumentNullException.ThrowIfNull(fileMatcher, nameof(fileMatcher));\n\n            _fileMatcher = fileMatcher;\n        }\n\n        public virtual void Dispose()\n        {\n            TemporaryDirectory?.Dispose();\n        }\n\n        public IEnumerable<FileInfo> GetFiles()\n        {\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            return TemporaryDirectory.Directory.EnumerateFiles(\"*\", SearchOption.AllDirectories);\n        }\n\n        public IEnumerable<FileInfo> GetFiles(Matcher matcher)\n        {\n            ArgumentNullException.ThrowIfNull(matcher, nameof(matcher));\n\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            DirectoryInfoWrapper directoryInfo = new(TemporaryDirectory.Directory);\n\n            return _fileMatcher.EnumerateMatches(directoryInfo, matcher);\n        }\n\n        public abstract ValueTask OpenAsync();\n        public abstract ValueTask SaveAsync();\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/ContainerProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class ContainerProvider : IContainerProvider\n    {\n        private readonly HashSet<string> _appxBundleExtensions;\n        private readonly HashSet<string> _appxExtensions;\n        private readonly IDirectoryService _directoryService;\n        private readonly IFileMatcher _fileMatcher;\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ILogger<IContainerProvider> _logger;\n        private readonly IMakeAppxCli _makeAppxCli;\n        private readonly HashSet<string> _nuGetExtensions;\n        private readonly HashSet<string> _zipExtensions;\n\n        // Dependency injection requires a public constructor.\n        public ContainerProvider(\n            ICertificateProvider certificateProvider,\n            IDirectoryService directoryService,\n            IFileMatcher fileMatcher,\n            IMakeAppxCli makeAppxCli,\n            ILogger<IContainerProvider> logger)\n        {\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(directoryService, nameof(directoryService));\n            ArgumentNullException.ThrowIfNull(fileMatcher, nameof(fileMatcher));\n            ArgumentNullException.ThrowIfNull(makeAppxCli, nameof(makeAppxCli));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _certificateProvider = certificateProvider;\n            _directoryService = directoryService;\n            _fileMatcher = fileMatcher;\n            _makeAppxCli = makeAppxCli;\n            _logger = logger;\n\n            _appxBundleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n            {\n                \".appxbundle\",\n                \".eappxbundle\",\n                \".emsixbundle\",\n                \".msixbundle\"\n            };\n\n            _appxExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n            {\n                \".appx\",\n                \".eappx\",\n                \".emsix\",\n                \".msix\"\n            };\n\n            _nuGetExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n            {\n                \".nupkg\",\n                \".snupkg\"\n            };\n\n            _zipExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n            {\n                \".appxupload\",\n                \".clickonce\",\n                \".msixupload\",\n                \".vsix\",\n                \".zip\"\n            };\n        }\n\n        public bool IsAppxBundleContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return _appxBundleExtensions.Contains(file.Extension);\n        }\n\n        public bool IsAppxContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return _appxExtensions.Contains(file.Extension);\n        }\n\n        public bool IsNuGetContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return _nuGetExtensions.Contains(file.Extension);\n        }\n\n        public bool IsZipContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return _zipExtensions.Contains(file.Extension);\n        }\n\n        public IContainer? GetContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            if (IsAppxBundleContainer(file))\n            {\n                return new AppxBundleContainer(file, _directoryService, _fileMatcher, _makeAppxCli, _logger);\n            }\n\n            if (IsAppxContainer(file))\n            {\n                return new AppxContainer(file, _certificateProvider, _directoryService, _fileMatcher, _makeAppxCli, _logger);\n            }\n\n            if (IsZipContainer(file))\n            {\n                return new ZipContainer(file, _directoryService, _fileMatcher, _logger);\n            }\n\n            if (IsNuGetContainer(file))\n            {\n                return new NuGetContainer(file, _directoryService, _fileMatcher, _logger);\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/IContainer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal interface IContainer : IDisposable\n    {\n        IEnumerable<FileInfo> GetFiles();\n        IEnumerable<FileInfo> GetFiles(Matcher matcher);\n\n        ValueTask OpenAsync();\n        ValueTask SaveAsync();\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/IContainerProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IContainerProvider\n    {\n        bool IsAppxBundleContainer(FileInfo file);\n        bool IsAppxContainer(FileInfo file);\n        bool IsNuGetContainer(FileInfo file);\n        bool IsZipContainer(FileInfo file);\n        IContainer? GetContainer(FileInfo file);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/NuGetContainer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing NuGet.Packaging.Signing;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetContainer : ZipContainer\n    {\n        internal NuGetContainer(\n            FileInfo zipFile,\n            IDirectoryService directoryService,\n            IFileMatcher fileMatcher,\n            ILogger logger)\n            : base(zipFile, directoryService, fileMatcher, logger)\n        {\n        }\n\n        public override ValueTask SaveAsync()\n        {\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            FileInfo signatureFile = new(\n                Path.Combine(\n                    TemporaryDirectory.Directory.FullName,\n                    SigningSpecifications.V1.SignaturePath));\n\n            if (signatureFile.Exists)\n            {\n                signatureFile.Delete();\n            }\n\n            return base.SaveAsync();\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Containers/ZipContainer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal class ZipContainer : Container\n    {\n        private readonly IDirectoryService _directoryService;\n        private readonly ILogger _logger;\n        private readonly FileInfo _zipFile;\n\n        internal ZipContainer(\n            FileInfo zipFile,\n            IDirectoryService directoryService,\n            IFileMatcher fileMatcher,\n            ILogger logger)\n            : base(fileMatcher)\n        {\n            ArgumentNullException.ThrowIfNull(zipFile, nameof(zipFile));\n            ArgumentNullException.ThrowIfNull(directoryService, nameof(directoryService));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _directoryService = directoryService;\n            _logger = logger;\n            _zipFile = zipFile;\n        }\n\n        public override ValueTask OpenAsync()\n        {\n            if (TemporaryDirectory is not null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            TemporaryDirectory = new TemporaryDirectory(_directoryService);\n\n            _logger.LogInformation(\n                Resources.OpeningContainer,\n                _zipFile.FullName,\n                TemporaryDirectory.Directory.FullName);\n\n            ZipFile.ExtractToDirectory(_zipFile.FullName, TemporaryDirectory.Directory.FullName);\n\n            return ValueTask.CompletedTask;\n        }\n\n        public override ValueTask SaveAsync()\n        {\n            if (TemporaryDirectory is null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            _logger.LogInformation(\n                Resources.SavingContainer,\n                _zipFile.FullName,\n                TemporaryDirectory.Directory.FullName);\n\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                string destinationFilePath = Path.Combine(temporaryDirectory.Directory.FullName, _zipFile.Name);\n\n                ZipFile.CreateFromDirectory(TemporaryDirectory.Directory.FullName, destinationFilePath, CompressionLevel.Optimal, false);\n\n                _zipFile.Delete();\n\n                File.Move(destinationFilePath, _zipFile.FullName, overwrite: true);\n\n                _zipFile.Refresh();\n            }\n\n            return ValueTask.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/AggregatingSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal sealed class AggregatingSigner : IAggregatingDataFormatSigner\n    {\n        private readonly IContainerProvider _containerProvider;\n        private readonly IDefaultDataFormatSigner _defaultSigner;\n        private readonly IFileMetadataService _fileMetadataService;\n        private readonly IMatcherFactory _matcherFactory;\n        private readonly IEnumerable<IDataFormatSigner> _signers;\n\n        // Dependency injection requires a public constructor.\n        public AggregatingSigner(\n            IEnumerable<IDataFormatSigner> signers,\n            IDefaultDataFormatSigner defaultSigner,\n            IContainerProvider containerProvider,\n            IFileMetadataService fileMetadataService,\n            IMatcherFactory matcherFactory)\n        {\n            ArgumentNullException.ThrowIfNull(signers, nameof(signers));\n            ArgumentNullException.ThrowIfNull(defaultSigner, nameof(defaultSigner));\n            ArgumentNullException.ThrowIfNull(containerProvider, nameof(containerProvider));\n            ArgumentNullException.ThrowIfNull(fileMetadataService, nameof(fileMetadataService));\n            ArgumentNullException.ThrowIfNull(matcherFactory, nameof(matcherFactory));\n\n            _signers = signers;\n            _defaultSigner = defaultSigner;\n            _containerProvider = containerProvider;\n            _fileMetadataService = fileMetadataService;\n            _matcherFactory = matcherFactory;\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            foreach (IDataFormatSigner signer in _signers)\n            {\n                if (signer.CanSign(file))\n                {\n                    return true;\n                }\n            }\n\n            string extension = file.Extension.ToLowerInvariant();\n\n            return extension switch\n            {\n                // archives\n                \".zip\" or \".appxupload\" or \".msixupload\" => true,\n                _ => false\n            };\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            if (options.RecurseContainers)\n            {\n                await SignContainerContentsAsync(files, options);\n            }\n\n            // split by code sign service and fallback to default\n\n            var grouped = (from signer in _signers\n                           from file in files\n                           where signer.CanSign(file)\n                           group file by signer into groups\n                           select groups).ToList();\n\n            // get all files and exclude existing; \n\n            // This is to catch PE files that don't have the correct extension set\n            var defaultFiles = files.Except(grouped.SelectMany(g => g))\n                                    .Where(_fileMetadataService.IsPortableExecutable)\n                                    .Select(f => new { _defaultSigner.Signer, f })\n                                    .GroupBy(a => a.Signer, k => k.f)\n                                    .SingleOrDefault(); // one group here\n\n            if (defaultFiles != null)\n            {\n                grouped.Add(defaultFiles);\n            }\n\n            await Task.WhenAll(grouped.Select(g => g.Key.SignAsync(g.ToList(), options)));\n        }\n\n        private async Task SignContainerContentsAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            // See if any of them are archives\n            List<FileInfo> archives = (from file in files\n                                       where _containerProvider.IsZipContainer(file) || _containerProvider.IsNuGetContainer(file)\n                                       select file).ToList();\n\n            // expand the archives and sign recursively first\n            List<IContainer> containers = new();\n\n            try\n            {\n                foreach (FileInfo archive in archives)\n                {\n                    IContainer container = _containerProvider.GetContainer(archive)!;\n\n                    await container.OpenAsync();\n\n                    containers.Add(container);\n                }\n\n                // See if there's any files in the expanded zip that we need to sign\n                List<FileInfo> allFiles = containers\n                    .SelectMany(container => GetFiles(container, options))\n                    .ToList();\n\n                if (allFiles.Count > 0)\n                {\n                    // Send the files from the archives through the aggregator to sign\n                    await SignAsync(allFiles, options);\n\n                    // After signing the contents, save the zip\n                    // For NuPkg, this step removes the signature too, but that's ok as it'll get signed below\n                    await Parallel.ForEachAsync(containers, (container, cancellationToken) => container.SaveAsync());\n                }\n            }\n            finally\n            {\n                containers.ForEach(tz => tz.Dispose());\n                containers.Clear();\n            }\n\n            // See if there's any appx's in here, process them recursively first to sign the inner files\n            List<FileInfo> appxs = (from file in files\n                                    where _containerProvider.IsAppxContainer(file)\n                                    select file).ToList();\n\n            // See if there's any appxbundles here, process them recursively first\n            // expand the archives and sign recursively first\n            // This will also update the publisher information to get it ready for signing\n            try\n            {\n                foreach (FileInfo appx in appxs)\n                {\n                    IContainer container = _containerProvider.GetContainer(appx)!;\n\n                    await container.OpenAsync();\n\n                    containers.Add(container);\n                }\n\n                // See if there's any files in the expanded zip that we need to sign\n                List<FileInfo> allFiles = containers\n                    .SelectMany(container => GetFiles(container, options))\n                    .ToList();\n\n                if (allFiles.Count > 0)\n                {\n                    // Send the files from the archives through the aggregator to sign\n                    await SignAsync(allFiles, options);\n                }\n\n                // Save the appx with the updated publisher info\n                await Parallel.ForEachAsync(containers, (container, cancellationToken) => container.SaveAsync());\n            }\n            finally\n            {\n                containers.ForEach(tz => tz.Dispose());\n                containers.Clear();\n            }\n\n            List<FileInfo> bundles = (from file in files\n                                      where _containerProvider.IsAppxBundleContainer(file)\n                                      select file).ToList();\n\n            try\n            {\n                foreach (FileInfo bundle in bundles)\n                {\n                    IContainer container = _containerProvider.GetContainer(bundle)!;\n\n                    await container.OpenAsync();\n\n                    containers.Add(container);\n                }\n\n                Matcher appxBundleFileMatcher = _matcherFactory.Create();\n\n                appxBundleFileMatcher.AddInclude(\"**/*.appx\");\n                appxBundleFileMatcher.AddInclude(\"**/*.msix\");\n\n                // See if there's any files in the expanded zip that we need to sign\n                List<FileInfo> allFiles = containers.SelectMany(tz => tz.GetFiles(appxBundleFileMatcher)).ToList();\n\n                if (allFiles.Count > 0)\n                {\n                    // Send the files from the archives through the aggregator to sign\n                    await SignAsync(allFiles, options);\n\n                    // After signing the contents, save the zip\n                    await Parallel.ForEachAsync(containers, (container, cancellationToken) => container.SaveAsync());\n                }\n            }\n            finally\n            {\n                containers.ForEach(tz => tz.Dispose());\n                containers.Clear();\n            }\n        }\n\n\n        public void CopySigningDependencies(FileInfo file, DirectoryInfo destination, SignOptions options)\n        {\n            // pass the handling for this down to the actual implementations\n            foreach (IDataFormatSigner signer in _signers)\n            {\n                if (signer.CanSign(file))\n                {\n                    signer.CopySigningDependencies(file, destination, options);\n                }\n            }\n        }\n\n        private static IEnumerable<FileInfo> GetFiles(IContainer container, SignOptions options)\n        {\n            IEnumerable<FileInfo> files;\n\n            if (options.Matcher is null)\n            {\n                // If not filtered, default to all\n                files = container.GetFiles();\n            }\n            else\n            {\n                files = container.GetFiles(options.Matcher);\n            }\n\n            if (options.AntiMatcher is not null)\n            {\n                IEnumerable<FileInfo> antiFiles = container.GetFiles(options.AntiMatcher);\n\n                files = files.Except(antiFiles, FileInfoComparer.Instance).ToList();\n            }\n\n            return files;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/AppInstallerServiceSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics.CodeAnalysis;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Xml.Linq;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    // Not really signing anything, but updates the manifest file with the\n    // correct publisher information\n    internal sealed class AppInstallerServiceSigner : IDataFormatSigner\n    {\n        // Windows 10, version 1709.\n        internal static readonly XNamespace AppInstaller2017 = XNamespace.Get(\"http://schemas.microsoft.com/appx/appinstaller/2017\");\n        // Windows 10, version 1803.\n        internal static readonly XNamespace AppInstaller2017_2 = XNamespace.Get(\"http://schemas.microsoft.com/appx/appinstaller/2017/2\");\n        // Windows 10, version 1809.\n        internal static readonly XNamespace AppInstaller2018 = XNamespace.Get(\"http://schemas.microsoft.com/appx/appinstaller/2018\");\n        // Windows version 21H2 build 22000\n        internal static readonly XNamespace AppInstaller2021 = XNamespace.Get(\"http://schemas.microsoft.com/appx/appinstaller/2021\");\n\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ILogger<IDataFormatSigner> _logger;\n\n        // Dependency injection requires a public constructor.\n        public AppInstallerServiceSigner(\n            ICertificateProvider certificateProvider,\n            ILogger<IDataFormatSigner> logger)\n        {\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _certificateProvider = certificateProvider;\n            _logger = logger;\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return string.Equals(file.Extension, \".appinstaller\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            _logger.LogInformation(Resources.EditingAppInstaller, files.Count());\n\n            using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync().ConfigureAwait(false))\n            {\n                // We need to open the files, and update the publisher value\n                foreach (FileInfo file in files)\n                {\n                    XDocument manifest;\n                    using (FileStream stream = file.OpenRead())\n                    {\n                        manifest = XDocument.Load(stream, LoadOptions.PreserveWhitespace);\n\n                        if (TryGetMainElement(manifest, out XElement? mainElement))\n                        {\n                            string publisher = certificate.SubjectName.Name;\n\n                            mainElement.SetAttributeValue(\"Publisher\", publisher);\n                        }\n                    }\n\n                    using (FileStream stream = file.Open(FileMode.Create, FileAccess.Write, FileShare.None))\n                    {\n                        manifest.Save(stream);\n                    }\n                }\n            }\n        }\n\n        internal static bool TryGetMainElement(XDocument appInstallerManifest, [NotNullWhen(true)] out XElement? mainElement)\n        {\n            mainElement = null;\n\n            XElement? rootElement = appInstallerManifest.Root;\n\n            if (rootElement is null)\n            {\n                return false;\n            }\n\n            XNamespace[] xmlNamespaces = [AppInstaller2017, AppInstaller2017_2, AppInstaller2018, AppInstaller2021];\n\n            foreach (XNamespace xmlNamespace in xmlNamespaces)\n            {\n                mainElement = rootElement.Element(xmlNamespace + \"MainBundle\") ?? rootElement.Element(xmlNamespace + \"MainPackage\");\n\n                if (mainElement is not null)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/AzureSignToolSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Runtime.ExceptionServices;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing AzureSign.Core;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal class AzureSignToolSigner : IAzureSignToolDataFormatSigner\n    {\n        // COM-based signing of .js and .vbs files requires an STA thread.\n        // See https://github.com/dotnet/sign/issues/880\n        private static readonly HashSet<string> StaThreadExtensions = new(StringComparer.OrdinalIgnoreCase)\n        {\n            \".js\",\n            \".vbs\"\n        };\n\n        internal const int S_OK = 0;\n\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ISignatureAlgorithmProvider _signatureAlgorithmProvider;\n        private readonly ILogger<IDataFormatSigner> _logger;\n        private readonly IReadOnlyList<ISignableFileType> _signableFileTypes;\n        private readonly IToolConfigurationProvider _toolConfigurationProvider;\n\n        // Dependency injection requires a public constructor.\n        public AzureSignToolSigner(\n            IToolConfigurationProvider toolConfigurationProvider,\n            ISignatureAlgorithmProvider signatureAlgorithmProvider,\n            ICertificateProvider certificateProvider,\n            ILogger<IDataFormatSigner> logger)\n        {\n            ArgumentNullException.ThrowIfNull(toolConfigurationProvider, nameof(toolConfigurationProvider));\n            ArgumentNullException.ThrowIfNull(signatureAlgorithmProvider, nameof(signatureAlgorithmProvider));\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _signatureAlgorithmProvider = signatureAlgorithmProvider;\n            _certificateProvider = certificateProvider;\n            _signatureAlgorithmProvider = signatureAlgorithmProvider;\n            _logger = logger;\n            _toolConfigurationProvider = toolConfigurationProvider;\n\n            _signableFileTypes = new List<ISignableFileType>()\n            {\n                // For PowerShell file extensions, see https://github.com/PowerShell/PowerShell/blob/2f4f585e7fe075f5c1669397ae738c554fa18391/src/System.Management.Automation/security/SecurityManager.cs#L97C1-L106C10\n                new SignableFileTypeByExtension(\n                    \".appx\",\n                    \".appxbundle\",\n                    \".cab\",\n                    \".cat\",\n                    \".cdxml\",       // PowerShell cmdlet definition XML\n                    \".dll\",\n                    \".eappx\",\n                    \".eappxbundle\",\n                    \".emsix\",\n                    \".emsixbundle\",\n                    \".exe\",\n                    \".js\",\n                    \".msi\",\n                    \".msix\",\n                    \".msixbundle\",\n                    \".msm\",\n                    \".msp\",\n                    \".mst\",\n                    \".ocx\",\n                    \".ps1\",         // PowerShell script files\n                    \".ps1xml\",      // PowerShell display configuration files\n                    \".psd1\",        // PowerShell data files\n                    \".psm1\",        // PowerShell module files\n                    \".stl\",\n                    \".sys\",\n                    \".vbs\",\n                    \".vxd\",\n                    \".winmd\"\n                ),\n                new DynamicsBusinessCentralAppFileType()\n            };\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            foreach (ISignableFileType signableFileType in _signableFileTypes)\n            {\n                if (signableFileType.IsMatch(file))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            _logger.LogInformation(Resources.AzureSignToolSignatureProviderSigning, files.Count());\n\n            TimeStampConfiguration timestampConfiguration;\n\n            if (options.TimestampService is null)\n            {\n                timestampConfiguration = TimeStampConfiguration.None;\n            }\n            else\n            {\n                timestampConfiguration = new(options.TimestampService.AbsoluteUri, options.TimestampHashAlgorithm, TimeStampType.RFC3161);\n            }\n\n            using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync())\n            using (RSA rsa = await _signatureAlgorithmProvider.GetRsaAsync())\n            using (AuthenticodeKeyVaultSigner signer = new(\n                rsa,\n                certificate,\n                options.FileHashAlgorithm,\n                timestampConfiguration))\n            {\n                // Partition files: STA-required files (.js, .vbs) are signed sequentially\n                // to avoid blocking ThreadPool threads (each STA call uses thread.Join()).\n                // Non-STA files are signed in parallel as before.\n                List<FileInfo> staFiles = new();\n                List<FileInfo> nonStaFiles = new();\n\n                foreach (FileInfo file in files)\n                {\n                    if (StaThreadExtensions.Contains(file.Extension))\n                    {\n                        staFiles.Add(file);\n                    }\n                    else\n                    {\n                        nonStaFiles.Add(file);\n                    }\n                }\n\n                foreach (FileInfo file in staFiles)\n                {\n                    if (!await SignAsync(signer, file, options))\n                    {\n                        string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, file.FullName);\n\n                        throw new SigningException(message);\n                    }\n                }\n\n                await Parallel.ForEachAsync(nonStaFiles, async (file, state) =>\n                {\n                    if (!await SignAsync(signer, file, options))\n                    {\n                        string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, file.FullName);\n\n                        throw new SigningException(message);\n                    }\n                });\n            }\n        }\n\n        // Inspired from https://github.com/squaredup/bettersigntool/blob/master/bettersigntool/bettersigntool/SignCommand.cs\n        private async Task<bool> SignAsync(\n            AuthenticodeKeyVaultSigner signer,\n            FileInfo file,\n            SignOptions options)\n        {\n            TimeSpan retry = TimeSpan.FromSeconds(5);\n            const int maxAttempts = 3;\n            int attempt = 1;\n\n            do\n            {\n                if (attempt > 1)\n                {\n                    _logger.LogInformation(Resources.SigningAttempt, attempt, maxAttempts, retry.TotalSeconds);\n                    await Task.Delay(retry);\n                    retry = TimeSpan.FromSeconds(Math.Pow(retry.TotalSeconds, 1.5));\n                }\n\n                if (RunSignTool(signer, file, options))\n                {\n                    return true;\n                }\n\n                ++attempt;\n\n            } while (attempt <= maxAttempts);\n\n            _logger.LogError(Resources.SigningFailedAfterAllAttempts);\n\n            return false;\n        }\n\n        private bool RunSignTool(AuthenticodeKeyVaultSigner signer, FileInfo file, SignOptions options)\n        {\n            FileInfo manifestFile = _toolConfigurationProvider.SignToolManifest;\n\n            _logger.LogInformation(Resources.SigningFile, file.FullName);\n\n            bool success = false;\n            int code = 0;\n\n            try\n            {\n                if (StaThreadExtensions.Contains(file.Extension))\n                {\n                    code = RunOnStaThread(() => SignFileCore(signer, file, options, manifestFile));\n                }\n                else\n                {\n                    code = SignFileCore(signer, file, options, manifestFile);\n                }\n\n                success = code == S_OK;\n            }\n            catch (Exception e)\n            {\n                _logger.LogError(e, e.Message);\n            }\n\n            if (success)\n            {\n                _logger.LogInformation(Resources.SigningSucceeded, file.FullName);\n                return true;\n            }\n\n            _logger.LogError(Resources.SigningFailedWithError, code);\n\n            return false;\n        }\n\n        internal virtual int SignFileCore(\n            AuthenticodeKeyVaultSigner signer,\n            FileInfo file,\n            SignOptions options,\n            FileInfo manifestFile)\n        {\n            using (Kernel32.ActivationContext ctx = new(manifestFile))\n            {\n                return signer.SignFile(\n                    file.FullName,\n                    options.Description ?? string.Empty,\n                    options.DescriptionUrl?.AbsoluteUri ?? string.Empty,\n                    pageHashing: null,\n                    _logger);\n            }\n        }\n\n        private static T RunOnStaThread<T>(Func<T> func)\n        {\n            if (!OperatingSystem.IsWindows())\n            {\n                throw new PlatformNotSupportedException();\n            }\n\n            T result = default!;\n            Exception? exception = null;\n\n            Thread thread = new(() =>\n            {\n                try\n                {\n                    result = func();\n                }\n                catch (Exception ex)\n                {\n                    exception = ex;\n                }\n            });\n\n            thread.SetApartmentState(ApartmentState.STA);\n            thread.Start();\n            thread.Join();\n\n            if (exception is not null)\n            {\n                ExceptionDispatchInfo.Capture(exception).Throw();\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/ClickOnceSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class ClickOnceSigner : RetryingSigner, IDataFormatSigner\n    {\n        private readonly Lazy<IAggregatingDataFormatSigner> _aggregatingSigner;\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ISignatureAlgorithmProvider _signatureAlgorithmProvider;\n        private readonly IMageCli _mageCli;\n        private readonly IManifestSigner _manifestSigner;\n        private readonly ParallelOptions _parallelOptions = new() { MaxDegreeOfParallelism = 4 };\n        private readonly IFileMatcher _fileMatcher;\n\n        // Dependency injection requires a public constructor.\n        public ClickOnceSigner(\n            ISignatureAlgorithmProvider signatureAlgorithmProvider,\n            ICertificateProvider certificateProvider,\n            IServiceProvider serviceProvider,\n            IMageCli mageCli,\n            IManifestSigner manifestSigner,\n            ILogger<IDataFormatSigner> logger,\n            IFileMatcher fileMatcher)\n            : base(logger)\n        {\n            ArgumentNullException.ThrowIfNull(signatureAlgorithmProvider, nameof(signatureAlgorithmProvider));\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n            ArgumentNullException.ThrowIfNull(mageCli, nameof(mageCli));\n            ArgumentNullException.ThrowIfNull(manifestSigner, nameof(manifestSigner));\n            ArgumentNullException.ThrowIfNull(fileMatcher, nameof(fileMatcher));\n\n            _signatureAlgorithmProvider = signatureAlgorithmProvider;\n            _certificateProvider = certificateProvider;\n            _mageCli = mageCli;\n            _manifestSigner = manifestSigner;\n            _fileMatcher = fileMatcher;\n\n            // Need to delay this as it'd create a dependency loop if directly in the ctor\n            _aggregatingSigner = new Lazy<IAggregatingDataFormatSigner>(() => serviceProvider.GetService<IAggregatingDataFormatSigner>()!);\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return file.Extension.ToLowerInvariant() switch\n            {\n                \".vsto\" or \".application\" => true,\n                _ => false\n            };\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            Logger.LogInformation(Resources.ClickOnceSignatureProviderSigning, files.Count());\n\n            var args = \"-a sha256RSA\";\n            if (!string.IsNullOrWhiteSpace(options.ApplicationName))\n            {\n                args += $@\" -n \"\"{options.ApplicationName}\"\"\";\n            }\n\n            Uri? timeStampUrl = options.TimestampService;\n\n            using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync())\n            using (RSA rsaPrivateKey = await _signatureAlgorithmProvider.GetRsaAsync())\n            {\n                // This outer loop is for a deployment manifest file (.application/.vsto).\n                await Parallel.ForEachAsync(files, _parallelOptions, async (file, state) =>\n                {\n                    // We need to be explicit about the order these files are signed in. The data files must be signed first\n                    // Then the .manifest file\n                    // Then the nested clickonce/vsto file\n                    // finally the top-level clickonce/vsto file\n                    // It's possible that there might not actually be a .manifest file or any data files if the user just\n                    // wants to re-sign an existing deployment manifest because e.g. the update URL has changed but nothing\n                    // else has. In that case we don't need to touch the other files and we can just sign the deployment manifest.\n\n                    // Look for the data files first - these are .deploy files\n                    // we need to rename them, sign, then restore the name\n\n                    DirectoryInfo clickOnceDirectory = file.Directory!;\n\n                    // get the files, _including_ the SignOptions, so that we only actually try to sign the files specified.\n                    // this is useful if e.g. you don't want to sign third-party assemblies that your application depends on\n                    // but you do still want to sign your own assemblies.\n                    List<FileInfo> filteredFiles = GetFiles(clickOnceDirectory, options).ToList();\n                    List<FileInfo> deployFilesToSign = filteredFiles\n                        .Where(f => \".deploy\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase))\n                        .ToList();\n                    List<FileInfo> contentFiles = new();\n\n                    RemoveDeployExtension(deployFilesToSign, contentFiles);\n\n                    List<FileInfo> filesToSign = contentFiles.ToList(); // copy it since we may add setup.exe\n                    IEnumerable<FileInfo> setupExe = filteredFiles.Where(f => \".exe\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase));\n                    filesToSign.AddRange(setupExe);\n\n                    // sign the inner files\n                    await _aggregatingSigner.Value.SignAsync(filesToSign!, options);\n\n                    // rename the rest of the deploy files since signing the manifest will need them.\n                    // this uses the overload of GetFiles() that ignores file matching options because we\n                    // require all files to be named correctly in order to generate valid manifests.\n                    List<FileInfo> filesExceptFiltered = GetFiles(clickOnceDirectory).Except(filteredFiles, FileInfoComparer.Instance).ToList();\n                    List<FileInfo> deployFiles = filesExceptFiltered\n                        .Where(f => \".deploy\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase))\n                        .ToList();\n\n                    RemoveDeployExtension(deployFiles, contentFiles);\n\n                    // at this point contentFiles has all deploy files renamed\n\n                    // Inner files are now signed\n                    // now look for the manifest file and sign that if we have one\n\n                    FileInfo? manifestFile = filteredFiles.SingleOrDefault(f => \".manifest\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase));\n\n                    string fileArgs = $@\"-update \"\"{manifestFile}\"\" {args}\";\n\n                    if (manifestFile is not null && !await SignAsync(fileArgs, manifestFile, rsaPrivateKey, certificate, options))\n                    {\n                        string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, manifestFile.FullName);\n\n                        throw new SigningException(message);\n                    }\n\n                    string publisherParam = string.Empty;\n\n                    if (string.IsNullOrEmpty(options.PublisherName))\n                    {\n                        string publisherName = certificate.SubjectName.Name;\n\n                        // get the DN. it may be quoted\n                        publisherParam = $@\"-pub \"\"{publisherName.Replace(\"\\\"\", \"\")}\"\"\";\n                    }\n                    else\n                    {\n                        publisherParam = $\"-pub \\\"{options.PublisherName}\\\"\";\n                    }\n\n                    // Now sign deployment manifest files (.application/.vsto).\n                    // Order by desending length to put the inner one first\n                    List<FileInfo> deploymentManifestFiles = filteredFiles\n                        .Where(f => \".vsto\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase) ||\n                                    \".application\".Equals(f.Extension, StringComparison.OrdinalIgnoreCase))\n                        .Select(f => new { file = f, f.FullName.Length })\n                        .OrderByDescending(f => f.Length)\n                        .Select(f => f.file)\n                        .ToList();\n\n                    foreach (FileInfo deploymentManifestFile in deploymentManifestFiles)\n                    {\n                        fileArgs = $@\"-update \"\"{deploymentManifestFile.FullName}\"\" {args} {publisherParam}\";\n                        if (manifestFile is not null)\n                        {\n                            fileArgs += $@\" -appm \"\"{manifestFile.FullName}\"\"\";\n                        }\n                        if (options.DescriptionUrl is not null)\n                        {\n                            fileArgs += $@\" -SupportURL {options.DescriptionUrl.AbsoluteUri}\";\n                        }\n\n                        if (!await SignAsync(fileArgs, deploymentManifestFile, rsaPrivateKey, certificate, options))\n                        {\n                            string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, deploymentManifestFile.FullName);\n\n                            throw new SigningException(message);\n                        }\n                    }\n\n                    // restore the .deploy files\n                    foreach (FileInfo contentFile in contentFiles)\n                    {\n                        File.Move(contentFile.FullName, $\"{contentFile.FullName}.deploy\");\n                    }\n                });\n            }\n        }\n\n        private static void RemoveDeployExtension(List<FileInfo> deployFilesToSign, List<FileInfo> contentFiles)\n        {\n            foreach (FileInfo deployFileToSign in deployFilesToSign)\n            {\n                // Rename to file without .deploy extension\n                // For example:\n                //      *  MyApp.dll.deploy => MyApp.dll\n                //      *  MyApp.exe.deploy => MyApp.exe\n                string contentFilePath = Path.Combine(\n                    deployFileToSign.DirectoryName!,\n                    Path.GetFileNameWithoutExtension(deployFileToSign.Name));\n                FileInfo contentFile = new(contentFilePath);\n\n                File.Move(deployFileToSign.FullName, contentFile.FullName);\n\n                contentFiles.Add(contentFile);\n            }\n        }\n\n        protected override async Task<bool> SignCoreAsync(string? args, FileInfo file, RSA rsaPrivateKey, X509Certificate2 certificate, SignOptions options)\n        {\n            int exitCode = await _mageCli.RunAsync(args);\n\n            if (exitCode == 0)\n            {\n                // Now add the signature\n                _manifestSigner.Sign(file, certificate, rsaPrivateKey, options);\n\n                return true;\n            }\n\n            Logger.LogError(Resources.SigningFailedWithError, exitCode);\n\n            return false;\n        }\n\n\n        private IEnumerable<FileInfo> GetFiles(DirectoryInfo clickOnceRoot)\n        {\n            return clickOnceRoot.EnumerateFiles(\"*\", SearchOption.AllDirectories);\n        }\n\n        private IEnumerable<FileInfo> GetFiles(DirectoryInfo clickOnceRoot, SignOptions options)\n        {\n            IEnumerable<FileInfo> files;\n\n            if (options.Matcher is null)\n            {\n                // If not filtered, default to all\n                files = GetFiles(clickOnceRoot);\n            }\n            else\n            {\n                files = _fileMatcher.EnumerateMatches(new DirectoryInfoWrapper(clickOnceRoot), options.Matcher);\n            }\n\n            if (options.AntiMatcher is not null)\n            {\n                IEnumerable<FileInfo> antiFiles = _fileMatcher.EnumerateMatches(new DirectoryInfoWrapper(clickOnceRoot), options.AntiMatcher);\n\n                files = files.Except(antiFiles, FileInfoComparer.Instance).ToList();\n            }\n            return files;\n        }\n\n        public void CopySigningDependencies(FileInfo deploymentManifestFile, DirectoryInfo destination, SignOptions signOptions)\n        {\n            // copy _all_ files, ignoring matching options, because we need them to be available to generate\n            // valid manifests.\n            foreach (FileInfo file in GetFiles(deploymentManifestFile.Directory!))\n            {\n                // don't copy the file itself because that's already taken care of (and we don't want a duplicate copy with the 'real' name)\n                // lying around since it'll get copied back and overwrite the signed one.\n                if (file.FullName != deploymentManifestFile.FullName)\n                {\n                    string relativeDestPath = Path.GetRelativePath(deploymentManifestFile.Directory!.FullName, file.FullName);\n                    string fullDestPath = Path.Combine(destination.FullName, relativeDestPath);\n                    Directory.CreateDirectory(Path.GetDirectoryName(fullDestPath!)!);\n                    file.CopyTo(fullDestPath, overwrite: true);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/DefaultSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Sign.Core\n{\n    internal sealed class DefaultSigner : IDefaultDataFormatSigner\n    {\n        public IDataFormatSigner Signer { get; }\n\n        // Dependency injection requires a public constructor.\n        public DefaultSigner(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            foreach (IDataFormatSigner signer in serviceProvider.GetServices<IDataFormatSigner>())\n            {\n                if (signer is IAzureSignToolDataFormatSigner)\n                {\n                    Signer = signer;\n\n                    return;\n                }\n            }\n\n            Signer = new DoNothingDefaultDataFormatSigner();\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            return Signer.CanSign(file);\n        }\n\n        public Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            return Signer.SignAsync(files, options);\n        }\n\n        private sealed class DoNothingDefaultDataFormatSigner : IDataFormatSigner\n        {\n            public bool CanSign(FileInfo file)\n            {\n                return false;\n            }\n\n            public Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n            {\n                throw new NotImplementedException();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/DistinguishedNameParser.cs",
    "content": "#pragma warning disable IDE0073 // The file header does not match the required text\n// The MIT License (MIT)\n// \n// Copyright (c) 2015 Kevin Jones\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nusing System.Runtime.InteropServices;\n\nnamespace Sign.Core\n{\n    // From https://github.com/vcsjones/FiddlerCert/blob/06642751314a9ff224cb37a1cd7c14b86062a119/VCSJones.FiddlerCert/DistinguishedNameParser.cs\n    internal static class DistinguishedNameParser\n    {\n        internal static Dictionary<string, List<string>> Parse(string distingishedName)\n        {\n            var result = new Dictionary<string, List<string>>(StringComparer.CurrentCultureIgnoreCase);\n            var distinguishedNamePtr = IntPtr.Zero;\n            try\n            {\n                distinguishedNamePtr = Marshal.StringToCoTaskMemUni(distingishedName);\n                //We need to copy the IntPtr.\n                //The copy is necessary because DsGetRdnW modifies the pointer to advance it. We need to keep\n                //The original so we can free it later, otherwise we'll leak memory.\n                var distinguishedNamePtrCopy = distinguishedNamePtr;\n                var pcDN = (uint)distingishedName.Length;\n                while (pcDN != 0 && Ntdsapi.DsGetRdnW(ref distinguishedNamePtrCopy, ref pcDN, out var ppKey, out var pcKey, out var ppVal, out var pcVal) == 0)\n                {\n                    if (pcKey == 0 || pcVal == 0)\n                    {\n                        continue;\n                    }\n\n                    var key = Marshal.PtrToStringUni(ppKey, (int)pcKey);\n                    var value = Marshal.PtrToStringUni(ppVal, (int)pcVal);\n                    if (result.ContainsKey(key))\n                    {\n                        result[key].Add(value);\n                    }\n                    else\n                    {\n                        result.Add(key, new List<string> { value });\n                    }\n\n                    if (pcDN == 0)\n                    {\n                        break;\n                    }\n                }\n\n                return result;\n\n            }\n            finally\n            {\n                Marshal.FreeCoTaskMem(distinguishedNamePtr);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/DynamicsBusinessCentralAppFileType.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class DynamicsBusinessCentralAppFileType : ISignableFileType\n    {\n        private const string FileExtension = \".app\";\n\n        private readonly byte[] _expectedHeader;\n\n        internal DynamicsBusinessCentralAppFileType()\n        {\n            _expectedHeader = new byte[] { 0x4e, 0x41, 0x56, 0x58 }; // NAVX\n        }\n\n        public bool IsMatch(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            if (!FileExtension.Equals(file.Extension, StringComparison.OrdinalIgnoreCase))\n            {\n                return false;\n            }\n\n            using (FileStream stream = file.OpenRead())\n            {\n                var header = new byte[_expectedHeader.Length];\n\n                if (stream.Read(header, offset: 0, header.Length) != header.Length)\n                {\n                    return false;\n                }\n\n                return header.SequenceEqual(_expectedHeader);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/IAggregatingDataFormatSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IAggregatingDataFormatSigner : IDataFormatSigner\n    {\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/IAzureSignToolDataFormatSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IAzureSignToolDataFormatSigner : IDataFormatSigner\n    {\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/IDataFormatSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IDataFormatSigner\n    {\n        bool CanSign(FileInfo file);\n        Task SignAsync(IEnumerable<FileInfo> files, SignOptions options);\n        // Some signature mechanisms (e.g. ClickOnce) require extra files alongside the main file to be signed.\n        // We can't rely on the user specifying everything (and even if we did, we sign all inputs in parallel\n        // so we'd have to add extra synchronisation) so this method instructs an implementation to grab all\n        // dependencies of a file and copy them to the specified directory.\n        void CopySigningDependencies(FileInfo file, DirectoryInfo destination, SignOptions options) { }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/IDefaultDataFormatSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IDefaultDataFormatSigner\n    {\n        IDataFormatSigner Signer { get; }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/IManifestSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    internal interface IManifestSigner\n    {\n        void Sign(FileInfo file, X509Certificate2 certificate, RSA rsaPrivateKey, SignOptions options);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/ISignableFileType.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface ISignableFileType\n    {\n        bool IsMatch(FileInfo file);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/ManifestSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Deployment.Internal.CodeSigning;\nusing System.Runtime.InteropServices;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Xml;\n\nnamespace Sign.Core\n{\n    internal sealed class ManifestSigner : IManifestSigner\n    {\n        public void Sign(FileInfo file, X509Certificate2 certificate, RSA rsaPrivateKey, SignOptions options)\n        {\n            try\n            {\n                XmlDocument manifestDom = new()\n                {\n                    PreserveWhitespace = true\n                };\n                manifestDom.Load(file.FullName);\n                SignedCmiManifest2 signedCmiManifest2 = new(manifestDom);\n                CmiManifestSigner2 signer;\n\n                if (rsaPrivateKey is RSACryptoServiceProvider rsaProvider)\n                {\n                    signer = new CmiManifestSigner2(SignedCmiManifest2.GetFixedRSACryptoServiceProvider(rsaProvider), certificate);\n                }\n                else\n                {\n                    signer = new CmiManifestSigner2(rsaPrivateKey, certificate);\n                }\n\n                if (options.TimestampService is null)\n                {\n                    signedCmiManifest2.Sign(signer);\n                }\n                else\n                {\n                    signedCmiManifest2.Sign(signer, options.TimestampService.AbsoluteUri);\n                }\n\n                manifestDom.Save(file.FullName);\n            }\n            catch (Exception ex)\n            {\n                throw Marshal.GetHRForException(ex) switch\n                {\n                    -2147012889 or -2147012867 => new ApplicationException(\"TimestampUrlNotFound\", ex),\n                    _ => new ApplicationException(ex.Message, ex)\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/NuGetSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetSigner : RetryingSigner, IDataFormatSigner\n    {\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ISignatureAlgorithmProvider _signatureAlgorithmProvider;\n        private readonly INuGetSignTool _nuGetSignTool;\n\n        // Dependency injection requires a public constructor.\n        public NuGetSigner(\n            ISignatureAlgorithmProvider signatureAlgorithmProvider,\n            ICertificateProvider certificateProvider,\n            INuGetSignTool nuGetSignTool,\n            ILogger<IDataFormatSigner> logger)\n            : base(logger)\n        {\n            ArgumentNullException.ThrowIfNull(signatureAlgorithmProvider, nameof(signatureAlgorithmProvider));\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(nuGetSignTool, nameof(nuGetSignTool));\n\n            _signatureAlgorithmProvider = signatureAlgorithmProvider;\n            _certificateProvider = certificateProvider;\n            _nuGetSignTool = nuGetSignTool;\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return string.Equals(file.Extension, \".nupkg\", StringComparison.OrdinalIgnoreCase)\n                || string.Equals(file.Extension, \".snupkg\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync())\n            using (RSA rsa = await _signatureAlgorithmProvider.GetRsaAsync())\n            {\n                var fileTaskPairs = files\n                    .Select(file => new\n                    {\n                        File = file,\n                        Task = SignAsync(args: null, file, rsa, certificate, options)\n                    })\n                    .ToList();\n\n                await Task.WhenAll(fileTaskPairs.Select(pair => pair.Task));\n\n                List<string> failedFiles = fileTaskPairs\n                    .Where(pair => !pair.Task.Result)\n                    .Select(pair => pair.File.FullName)\n                    .ToList();\n\n                if (failedFiles.Count > 0)\n                {\n                    string failedFilePaths = string.Join(\", \", failedFiles);\n                    string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, failedFilePaths);\n\n                    throw new SigningException(message);\n                }\n            }\n        }\n\n        protected override Task<bool> SignCoreAsync(string? args, FileInfo file, RSA rsaPrivateKey, X509Certificate2 certificate, SignOptions options)\n        {\n            return _nuGetSignTool.SignAsync(file, rsaPrivateKey, certificate, options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/RSAPKCS1SHA256SignatureDescription.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    // This type and its default constructor are public because:\n    //   \"Algorithms added to CryptoConfig must be accessible from outside their assembly.\"\n    // See https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig.addalgorithm?view=net-7.0#exceptions\n    public sealed class RSAPKCS1SHA256SignatureDescription : RSAPKCS1SignatureDescription\n    {\n        public RSAPKCS1SHA256SignatureDescription()\n            : base(\"SHA256\")\n        {\n        }\n\n        public sealed override HashAlgorithm CreateDigest()\n        {\n            return SHA256.Create();\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/RSAPKCS1SignatureDescription.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    public abstract class RSAPKCS1SignatureDescription : SignatureDescription\n    {\n        public RSAPKCS1SignatureDescription(string hashAlgorithmName)\n        {\n            KeyAlgorithm = typeof(RSA).AssemblyQualifiedName;\n            FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).AssemblyQualifiedName;\n            DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).AssemblyQualifiedName;\n            DigestAlgorithm = hashAlgorithmName;\n        }\n\n        public sealed override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)\n        {\n            var item = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm!)!;\n            item.SetKey(key);\n            item.SetHashAlgorithm(DigestAlgorithm!);\n            return item;\n        }\n\n        public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)\n        {\n            var item = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm!)!;\n            item.SetKey(key);\n            item.SetHashAlgorithm(DigestAlgorithm!);\n            return item;\n        }\n\n        public abstract override HashAlgorithm CreateDigest();\n    }\n}"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/RetryingSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal abstract class RetryingSigner\n    {\n        protected ILogger Logger { get; }\n\n        // Non-private for testing purposes.\n        internal TimeSpan Retry { get; set; } = TimeSpan.FromSeconds(5);\n\n        protected RetryingSigner(ILogger logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            Logger = logger;\n        }\n\n        protected abstract Task<bool> SignCoreAsync(string? args, FileInfo file, RSA rsaPrivateKey, X509Certificate2 certificate, SignOptions options);\n\n        // Inspired from https://github.com/squaredup/bettersigntool/blob/master/bettersigntool/bettersigntool/SignCommand.cs\n        protected async Task<bool> SignAsync(string? args, FileInfo file, RSA rsaPrivateKey, X509Certificate2 publicCertificate, SignOptions options)\n        {\n            TimeSpan retry = Retry;\n            const int maxAttempts = 3;\n            var attempt = 1;\n\n            do\n            {\n                if (attempt > 1)\n                {\n                    Logger.LogInformation(Resources.SigningAttempt, attempt, maxAttempts, retry.TotalSeconds);\n                    await Task.Delay(retry);\n                    retry = TimeSpan.FromSeconds(Math.Pow(retry.TotalSeconds, 1.5));\n                }\n\n                if (await SignCoreAsync(args, file, rsaPrivateKey, publicCertificate, options))\n                {\n                    Logger.LogInformation(Resources.SigningSucceeded, file.FullName);\n                    return true;\n                }\n\n                attempt++;\n\n            } while (attempt <= maxAttempts);\n\n            Logger.LogError(Resources.SigningFailedAfterAllAttempts);\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/SignOptions.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal sealed class SignOptions\n    {\n        internal string? ApplicationName { get; }\n        internal string? PublisherName { get; }\n        internal string? Description { get; }\n        internal Uri? DescriptionUrl { get; }\n        internal Matcher? Matcher { get; }\n        internal Matcher? AntiMatcher { get; }\n        internal HashAlgorithmName FileHashAlgorithm { get; } = HashAlgorithmName.SHA256;\n        internal HashAlgorithmName TimestampHashAlgorithm { get; } = HashAlgorithmName.SHA256;\n        internal Uri TimestampService { get; }\n        internal bool RecurseContainers { get; }\n\n        internal SignOptions(\n            string? applicationName,\n            string? publisherName,\n            string? description,\n            Uri? descriptionUrl,\n            HashAlgorithmName fileHashAlgorithm,\n            HashAlgorithmName timestampHashAlgorithm,\n            Uri timestampService,\n            Matcher? matcher,\n            Matcher? antiMatcher,\n            bool recurseContainers)\n        {\n            ApplicationName = applicationName;\n            PublisherName = publisherName;\n            Description = description;\n            DescriptionUrl = descriptionUrl;\n            FileHashAlgorithm = fileHashAlgorithm;\n            TimestampHashAlgorithm = timestampHashAlgorithm;\n            TimestampService = timestampService;\n            Matcher = matcher;\n            AntiMatcher = antiMatcher;\n            RecurseContainers = recurseContainers;\n        }\n\n        internal SignOptions(HashAlgorithmName fileHashAlgorithm, Uri timestampService)\n            : this(applicationName: null, publisherName: null, description: null, descriptionUrl: null,\n                  fileHashAlgorithm, HashAlgorithmName.SHA256, timestampService, matcher: null,\n                  antiMatcher: null, recurseContainers: true)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/SignableFileTypeByExtension.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class SignableFileTypeByExtension : ISignableFileType\n    {\n        private readonly HashSet<string> _fileExtensions;\n\n        internal SignableFileTypeByExtension(params string[] fileExtensions)\n        {\n            ArgumentNullException.ThrowIfNull(fileExtensions, nameof(fileExtensions));\n\n            if (fileExtensions.Length == 0)\n            {\n                throw new ArgumentException(Resources.ArgumentCannotBeEmpty, nameof(fileExtensions));\n            }\n\n            _fileExtensions = new HashSet<string>(fileExtensions, StringComparer.OrdinalIgnoreCase);\n        }\n\n        public bool IsMatch(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return _fileExtensions.Contains(file.Extension);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/DataFormatSigners/VsixSigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class VsixSigner : RetryingSigner, IDataFormatSigner\n    {\n        private readonly ICertificateProvider _certificateProvider;\n        private readonly ISignatureAlgorithmProvider _signatureAlgorithmProvider;\n        private readonly IVsixSignTool _vsixSignTool;\n\n        // Dependency injection requires a public constructor.\n        public VsixSigner(\n            ISignatureAlgorithmProvider signatureAlgorithmProvider,\n            ICertificateProvider certificateProvider,\n            IVsixSignTool vsixSignTool,\n            ILogger<IDataFormatSigner> logger)\n            : base(logger)\n        {\n            ArgumentNullException.ThrowIfNull(signatureAlgorithmProvider, nameof(signatureAlgorithmProvider));\n            ArgumentNullException.ThrowIfNull(certificateProvider, nameof(certificateProvider));\n            ArgumentNullException.ThrowIfNull(vsixSignTool, nameof(vsixSignTool));\n\n            _signatureAlgorithmProvider = signatureAlgorithmProvider;\n            _certificateProvider = certificateProvider;\n            _vsixSignTool = vsixSignTool;\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            return string.Equals(file.Extension, \".vsix\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        public async Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(files, nameof(files));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            Logger.LogInformation(Resources.VsixSignatureProviderSigning, files.Count());\n\n            using (X509Certificate2 certificate = await _certificateProvider.GetCertificateAsync())\n            using (RSA rsa = await _signatureAlgorithmProvider.GetRsaAsync())\n            {\n                var fileTaskPairs = files\n                    .Select(file => new\n                    {\n                        File = file,\n                        Task = SignAsync(args: null, file, rsa, certificate, options)\n                    })\n                    .ToList();\n\n                await Task.WhenAll(fileTaskPairs.Select(pair => pair.Task));\n\n                List<string> failedFiles = fileTaskPairs\n                    .Where(pair => !pair.Task.Result)\n                    .Select(pair => pair.File.FullName)\n                    .ToList();\n\n                if (failedFiles.Count > 0)\n                {\n                    string failedFilePaths = string.Join(\", \", failedFiles);\n                    string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, failedFilePaths);\n\n                    throw new SigningException(message);\n                }\n            }\n        }\n\n        protected override async Task<bool> SignCoreAsync(string? args, FileInfo file, RSA rsaPrivateKey, X509Certificate2 certificate, SignOptions options)\n        {\n            // Dual isn't supported, use Sha256\n            SignConfigurationSet configuration = new(\n                options.FileHashAlgorithm,\n                options.FileHashAlgorithm,\n                rsaPrivateKey,\n                certificate);\n\n            return await _vsixSignTool.SignAsync(file, configuration, options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/ExitCode.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class ExitCode\n    {\n        internal const int Success = 0;\n        internal const int InvalidOptions = 1;\n        internal const int Failed = 2;\n        internal const int NoInputsFound = 3;\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/FileListReader.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal sealed class FileListReader : IFileListReader\n    {\n        private readonly IMatcherFactory _matcherFactory;\n\n        // Dependency injection requires a public constructor.\n        public FileListReader(IMatcherFactory matcherFactory)\n        {\n            ArgumentNullException.ThrowIfNull(matcherFactory, nameof(matcherFactory));\n\n            _matcherFactory = matcherFactory;\n        }\n\n        public void Read(StreamReader reader, out Matcher matcher, out Matcher antiMatcher)\n        {\n            ArgumentNullException.ThrowIfNull(reader);\n\n            List<string> globs = new();\n            List<string> antiglobs = new();\n            string? line;\n\n            while ((line = reader.ReadLine()) is not null)\n            {\n                // don't allow parent directory traversal\n                line = line.Replace(@\"..\\\", \"\").Replace(\"../\", \"\");\n\n                if (!string.IsNullOrWhiteSpace(line))\n                {\n                    if (line.StartsWith(\"!\", StringComparison.Ordinal))\n                    {\n                        antiglobs.Add(line[1..]);\n                    }\n                    else\n                    {\n                        globs.Add(line);\n                    }\n                }\n            }\n\n            matcher = Globber.CreateMatcher(_matcherFactory, globs);\n            antiMatcher = Globber.CreateMatcher(_matcherFactory, antiglobs);\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/FileMatcher.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\n\nnamespace Sign.Core\n{\n    internal sealed class FileMatcher : IFileMatcher\n    {\n        private readonly Func<string, string> _normalizeSlashes;\n\n        public FileMatcher()\n        {\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\n            {\n                _normalizeSlashes = (string path) => path.Replace('/', Path.DirectorySeparatorChar);\n            }\n            else\n            {\n                _normalizeSlashes = _ => _;\n            }\n        }\n\n        public IEnumerable<FileInfo> EnumerateMatches(DirectoryInfoBase directory, Matcher matcher)\n        {\n            ArgumentNullException.ThrowIfNull(directory, nameof(directory));\n            ArgumentNullException.ThrowIfNull(matcher, nameof(matcher));\n\n            PatternMatchingResult result = matcher.Execute(directory);\n\n            return result.Files.Select(file => new FileInfo(Path.Combine(directory.FullName, _normalizeSlashes(file.Path))));\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/Globber.cs",
    "content": "#pragma warning disable IDE0073 // The file header does not match the required text\n// The MIT License (MIT)\n// \n// Copyright (c) 2014 Dave Glick\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n#pragma warning disable CS8600\n\nusing System.Globalization;\nusing System.Text.RegularExpressions;\nusing Microsoft.Extensions.FileSystemGlobbing;\n\n// \"Borrowed\" from https://github.com/Wyamio/Wyam/blob/c7a26da931477a48006f6ebc574c074458719774/src/core/Wyam.Core/IO/Globbing/Globber.cs\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Helper methods to work with globbing patterns.\n    /// </summary>\n    internal sealed class Globber\n    {\n        static readonly Regex HasBraces = new Regex(@\"\\{.*\\}\");\n        static readonly Regex NumericSet = new Regex(@\"^\\{(-?[0-9]+)\\.\\.(-?[0-9]+)\\}\");\n\n        internal static Matcher CreateMatcher(IMatcherFactory matcherFactory, IReadOnlyList<string> patterns)\n        {\n            ArgumentNullException.ThrowIfNull(matcherFactory, nameof(matcherFactory));\n            ArgumentNullException.ThrowIfNull(patterns, nameof(patterns));\n\n            // Initially based on code from Reliak.FileSystemGlobbingExtensions (https://github.com/reliak/Reliak.FileSystemGlobbingExtensions)\n\n            Matcher matcher = matcherFactory.Create();\n\n            // Expand braces\n            var expandedPatterns = patterns\n                .SelectMany(ExpandBraces)\n                .Select(f => f.Replace(\"\\\\{\", \"{\").Replace(\"\\\\}\", \"}\")); // Unescape braces\n\n            // Add the patterns, any that start with ! are exclusions\n            foreach (var expandedPattern in expandedPatterns)\n            {\n                var isExclude = expandedPattern[0] == '!';\n                var finalPattern = isExclude ? expandedPattern.Substring(1) : expandedPattern;\n                finalPattern = finalPattern\n                    .Replace(\"\\\\!\", \"!\") // Unescape negation\n                    .Replace(\"\\\\\", \"/\"); // Normalize slashes\n\n                // Add exclude or include pattern to matcher\n                if (isExclude)\n                {\n                    matcher.AddExclude(finalPattern);\n                }\n                else\n                {\n                    matcher.AddInclude(finalPattern);\n                }\n            }\n\n            return matcher;\n        }\n\n        /// <summary>Expands all brace ranges in a pattern, returning a sequence containing every possible combination.</summary>\n        /// <param name=\"pattern\">The pattern to expand.</param>\n        /// <returns>The expanded globbing patterns.</returns>\n        private static IEnumerable<string> ExpandBraces(string pattern)\n        {\n            // Initially based on code from Minimatch (https://github.com/SLaks/Minimatch/blob/master/Minimatch/Minimatcher.cs)\n            // Brace expansion:\n            // a{b,c}d -> abd acd\n            // a{b,}c -> abc ac\n            // a{0..3}d -> a0d a1d a2d a3d\n            // a{b,c{d,e}f}g -> abg acdfg acefg\n            // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg\n            //\n            // Invalid sets are not expanded.\n            // a{2..}b -> a{2..}b\n            // a{b}c -> a{b}c\n\n            if (!HasBraces.IsMatch(pattern))\n            {\n                // shortcut. no need to expand.\n                return new[] { pattern };\n            }\n\n            var escaping = false;\n            int i;\n\n            // examples and comments refer to this particular pattern:\n            // a{b,c{d,e},{f,g}h}x{y,z}\n            // expected:\n            // abxy\n            // abxz\n            // acdxy\n            // acdxz\n            // acexy\n            // acexz\n            // afhxy\n            // afhxz\n            // aghxy\n            // aghxz\n\n            // everything before the first \\{ is just a prefix.\n            // So, we pluck that off, and work with the rest,\n            // and then prepend it to everything we find.\n            if (pattern[0] != '{')\n            {\n                string prefix = null;\n                for (i = 0; i < pattern.Length; i++)\n                {\n                    var c = pattern[i];\n                    if (c == '\\\\')\n                    {\n                        escaping = !escaping;\n                    }\n                    else if (c == '{' && !escaping)\n                    {\n                        prefix = pattern.Substring(0, i);\n                        break;\n                    }\n                    else\n                    {\n                        escaping = false;\n                    }\n                }\n\n                // actually no sets, all { were escaped.\n                if (prefix == null)\n                {\n                    // no sets\n                    return new[] { pattern };\n                }\n\n                return ExpandBraces(pattern.Substring(i)).Select(t =>\n                {\n                    var neg = string.Empty;\n\n                    // Check for negated subpattern\n                    if (t.Length > 0 && t[0] == '!')\n                    {\n                        if (prefix[0] != '!')\n                        {\n                            // Only add a new negation if there isn't already one\n                            neg = \"!\";\n                        }\n                        t = t.Substring(1);\n                    }\n\n                    // Remove duplicated path separators (can happen when there's an empty expansion like \"baz/{foo,}/bar\")\n                    if (t.Length > 0 && t[0] == '/' && prefix[prefix.Length - 1] == '/')\n                    {\n                        t = t.Substring(1);\n                    }\n\n                    return neg + prefix + t;\n                });\n            }\n\n            // now we have something like:\n            // {b,c{d,e},{f,g}h}x{y,z}\n            // walk through the set, expanding each part, until\n            // the set ends.  then, we'll expand the suffix.\n            // If the set only has a single member, then'll put the {} back\n\n            // first, handle numeric sets, since they're easier\n            var numset = NumericSet.Match(pattern);\n            if (numset.Success)\n            {\n                // console.error(\"numset\", numset[1], numset[2])\n                var suf = ExpandBraces(pattern.Substring(numset.Length)).ToList();\n                int start = int.Parse(numset.Groups[1].Value, NumberFormatInfo.CurrentInfo),\n                end = int.Parse(numset.Groups[2].Value, NumberFormatInfo.CurrentInfo),\n                inc = start > end ? -1 : 1;\n                var retVal = new List<string>();\n                for (var w = start; w != (end + inc); w += inc)\n                {\n                    // append all the suffixes\n                    retVal.AddRange(suf.Select(t => w + t));\n                }\n                return retVal;\n            }\n\n            // ok, walk through the set\n            // We hope, somewhat optimistically, that there\n            // will be a } at the end.\n            // If the closing brace isn't found, then the pattern is\n            // interpreted as braceExpand(\"\\\\\" + pattern) so that\n            // the leading \\{ will be interpreted literally.\n            var depth = 1;\n            var set = new List<string>();\n            var member = string.Empty;\n            escaping = false;\n\n            for (i = 1 /* skip the \\{ */; i < pattern.Length && depth > 0; i++)\n            {\n                var c = pattern[i];\n\n                if (escaping)\n                {\n                    escaping = false;\n                    member += \"\\\\\" + c;\n                }\n                else\n                {\n                    switch (c)\n                    {\n                        case '\\\\':\n                            escaping = true;\n                            continue;\n\n                        case '{':\n                            depth++;\n                            member += \"{\";\n                            continue;\n\n                        case '}':\n                            depth--;\n\n                            // if this closes the actual set, then we're done\n                            if (depth == 0)\n                            {\n                                set.Add(member);\n                                member = string.Empty;\n\n                                // pluck off the close-brace\n                                break;\n                            }\n                            else\n                            {\n                                member += c;\n                                continue;\n                            }\n\n                        case ',':\n                            if (depth == 1)\n                            {\n                                set.Add(member);\n                                member = string.Empty;\n                            }\n                            else\n                            {\n                                member += c;\n                            }\n                            continue;\n\n                        default:\n                            member += c;\n                            continue;\n                    } // switch\n                } // else\n            } // for\n\n            // now we've either finished the set, and the suffix is\n            // pattern.substr(i), or we have *not* closed the set,\n            // and need to escape the leading brace\n            if (depth != 0)\n            {\n                // didn't close pattern\n                return ExpandBraces(\"\\\\\" + pattern);\n            }\n\n            // [\"b\", \"c{d,e}\",\"{f,g}h\"] -> [\"b\", \"cd\", \"ce\", \"fh\", \"gh\"]\n            var addBraces = set.Count == 1;\n\n            set = set.SelectMany(ExpandBraces).ToList();\n\n            if (addBraces)\n            {\n                set = set.Select(s => \"{\" + s + \"}\").ToList();\n            }\n\n            // now attach the suffixes.\n            // x{y,z} -> [\"xy\", \"xz\"]\n            // console.error(\"set\", set)\n            // console.error(\"suffix\", pattern.substr(i))\n            return ExpandBraces(pattern.Substring(i)).SelectMany(suf =>\n            {\n                var negated = false;\n                if (suf.Length > 0 && suf[0] == '!')\n                {\n                    negated = true;\n                    suf = suf.Substring(1);\n                }\n                return set.Select(s =>\n                {\n                    var neg = string.Empty;\n                    if (negated && (s.Length == 0 || s[0] != '!'))\n                    {\n                        // Only add a new negation if there isn't already one\n                        neg = \"!\";\n                    }\n                    return neg + s + suf;\n                });\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/IFileListReader.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal interface IFileListReader\n    {\n        void Read(StreamReader reader, out Matcher matcher, out Matcher antiMatcher);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/IFileMatcher.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\n\nnamespace Sign.Core\n{\n    internal interface IFileMatcher\n    {\n        IEnumerable<FileInfo> EnumerateMatches(DirectoryInfoBase directory, Matcher matcher);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/IMatcherFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal interface IMatcherFactory\n    {\n        Matcher Create();\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileList/MatcherFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core\n{\n    internal sealed class MatcherFactory : IMatcherFactory\n    {\n        internal StringComparison StringComparison { get; } = StringComparison.OrdinalIgnoreCase;\n\n        public Matcher Create()\n        {\n            return new Matcher(StringComparison);\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/AppRootDirectoryLocator.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class AppRootDirectoryLocator : IAppRootDirectoryLocator\n    {\n        private static readonly Lazy<DirectoryInfo> LazyDirectory = new(GetAppRootDirectory);\n\n        public DirectoryInfo Directory => LazyDirectory.Value;\n\n        // Dependency injection requires a public constructor.\n        public AppRootDirectoryLocator()\n        {\n        }\n\n        private static DirectoryInfo GetAppRootDirectory()\n        {\n            string filePath = typeof(AppRootDirectoryLocator).Assembly.Location;\n            FileInfo file = new(filePath);\n\n            return file.Directory!;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/DirectoryService.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class DirectoryService : IDirectoryService\n    {\n        private readonly ILogger<IDirectoryService> _logger;\n        private readonly ConcurrentQueue<DirectoryInfo> _temporaryDirectories = new();\n\n        // Dependency injection requires a public constructor.\n        public DirectoryService(ILogger<IDirectoryService> logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _logger = logger;\n        }\n\n        public DirectoryInfo CreateTemporaryDirectory()\n        {\n            string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());\n\n            _logger.LogTrace(Resources.CreatingDirectory, path);\n\n            DirectoryInfo directory = Directory.CreateDirectory(path);\n\n            _temporaryDirectories.Enqueue(directory);\n\n            return directory;\n        }\n\n        public void Delete(DirectoryInfo directory)\n        {\n            ArgumentNullException.ThrowIfNull(directory, nameof(directory));\n\n            directory.Refresh();\n\n            if (!directory.Exists)\n            {\n                return;\n            }\n\n            _logger.LogTrace(Resources.DeletingDirectory, directory.FullName);\n\n\n            try\n            {\n                directory.Delete(recursive: true);\n\n            }\n            catch (Exception ex)\n            {\n                _logger.LogWarning(ex, Resources.ExceptionWhileDeletingDirectory, directory.FullName);\n\n                return;\n            }\n\n            _logger.LogTrace(Resources.DeletedDirectory, directory.FullName);\n\n            // The directory is not guaranteed to be gone since there could be\n            // other open handles. Wait, up to half a second, until the directory is gone.\n            for (var i = 0; directory.Exists && i < 5; ++i)\n            {\n                Thread.Sleep(100);\n\n                directory.Refresh();\n            }\n\n            if (directory.Exists)\n            {\n                _logger.LogTrace(Resources.DirectoryNotDeleted, directory.FullName);\n            }\n        }\n\n        public void Dispose()\n        {\n            while (_temporaryDirectories.TryDequeue(out DirectoryInfo? temporaryDirectory))\n            {\n                Delete(temporaryDirectory);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/FileInfoComparer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Sign.Core\n{\n    internal sealed class FileInfoComparer : IEqualityComparer<FileInfo>\n    {\n        internal static FileInfoComparer Instance { get; } = new FileInfoComparer();\n\n        public bool Equals(FileInfo? x, FileInfo? y)\n        {\n            if (ReferenceEquals(x, y))\n            {\n                return true;\n            }\n\n            if (x is null || y is null)\n            {\n                return false;\n            }\n\n            return string.Equals(x.FullName, y.FullName, StringComparison.Ordinal);\n        }\n\n        public int GetHashCode([DisallowNull] FileInfo obj)\n        {\n            return obj.FullName.GetHashCode();\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/FileMetadataService.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class FileMetadataService : IFileMetadataService\n    {\n        public bool IsPortableExecutable(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            using (FileStream stream = file.OpenRead())\n            {\n                var buffer = new byte[2];\n                if (stream.CanRead)\n                {\n                    int read = stream.Read(buffer, offset: 0, count: 2);\n                    if (read == 2)\n                    {\n                        // Look for the magic MZ header \n                        return buffer[0] == 0x4d && buffer[1] == 0x5a;\n                    }\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/IAppRootDirectoryLocator.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IAppRootDirectoryLocator\n    {\n        DirectoryInfo Directory { get; }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/IDirectoryService.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IDirectoryService : IDisposable\n    {\n        DirectoryInfo CreateTemporaryDirectory();\n        void Delete(DirectoryInfo directory);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/IFileMetadataService.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IFileMetadataService\n    {\n        bool IsPortableExecutable(FileInfo file);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/ITemporaryDirectory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface ITemporaryDirectory : IDisposable\n    {\n        DirectoryInfo Directory { get; }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/FileSystem/TemporaryDirectory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class TemporaryDirectory : ITemporaryDirectory\n    {\n        private readonly IDirectoryService _directoryService;\n\n        public DirectoryInfo Directory { get; }\n\n        internal TemporaryDirectory(IDirectoryService directoryService)\n        {\n            ArgumentNullException.ThrowIfNull(directoryService, nameof(directoryService));\n\n            Directory = directoryService.CreateTemporaryDirectory();\n\n            _directoryService = directoryService;\n        }\n\n        public void Dispose()\n        {\n            _directoryService.Delete(Directory);\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/GlobalSuppressions.cs",
    "content": "﻿#pragma warning disable IDE0073 // The file header does not match the required text\n// This file is used by Code Analysis to maintain SuppressMessage\n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given\n// a specific target and scoped to a namespace, type, member, etc.\n\nusing System.Diagnostics.CodeAnalysis;\n[assembly: SuppressMessage(\"Interoperability\", \"CA1416:Validate platform compatibility\", Justification = \"This program only supports Windows at this time.\", Scope = \"member\", Target = \"~M:Sign.Core.ManifestSigner.Sign(System.IO.FileInfo,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.RSA,Sign.Core.SignOptions)\")]\n"
  },
  {
    "path": "src/Sign.Core/ICertificateProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Top-level interface for certificate services such as Azure Key Vault and Certificate Store Manager.\n    /// </summary>\n    internal interface ICertificateProvider\n    {\n        /// <summary>\n        /// Acquires the certificate from the initialized certificate service.\n        /// </summary>\n        /// <returns>An <see cref=\"X509Certificate2\"/> certificate acquired from the initialized certificate service.</returns>\n        Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken = default);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/IServiceProviderFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal interface IServiceProviderFactory\n    {\n        IServiceProvider Create(\n            LogLevel logLevel = LogLevel.Information,\n            ILoggerProvider? loggerProvider = null,\n            Action<IServiceCollection>? addServices = null);\n\n        void AddServices(Action<IServiceCollection> addServices);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/ISignatureAlgorithmProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    internal interface ISignatureAlgorithmProvider\n    {\n        Task<RSA> GetRsaAsync(CancellationToken cancellationToken = default);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/ISignatureProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface ISignatureProvider\n    {\n        ISignatureAlgorithmProvider GetSignatureAlgorithmProvider(IServiceProvider serviceProvider);\n        ICertificateProvider GetCertificateProvider(IServiceProvider serviceProvider);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/ISigner.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    internal interface ISigner\n    {\n        Task<int> SignAsync(\n            IReadOnlyList<FileInfo> inputFiles,\n            string? outputFile,\n            FileInfo? fileList,\n            bool recurseContainers,\n            DirectoryInfo baseDirectory,\n            string? applicationName,\n            string? publisherName,\n            string? description,\n            Uri? descriptionUrl,\n            Uri timestampUrl,\n            int maxConcurrency,\n            HashAlgorithmName fileHashAlgorithm,\n            HashAlgorithmName timestampHashAlgorithm);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Native/Kernel32.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.ComponentModel;\nusing System.Runtime.InteropServices;\n\nnamespace Sign.Core\n{\n#pragma warning disable IDE1006 // Naming Styles\n    internal static partial class Kernel32\n    {\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool SetDllDirectoryW(\n            [MarshalAs(UnmanagedType.LPWStr)] string lpPathName);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true)]\n        public static extern IntPtr LoadLibraryW(\n            [MarshalAs(UnmanagedType.LPWStr)] string path);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        public static extern IntPtr CreateActCtxW(ref ACTCTX pActCtx);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, PreserveSig = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool DeactivateActCtx(int dwFlags, IntPtr lpCookie);\n\n        [DllImport(\"kernel32.dll\", PreserveSig = true)]\n        public static extern void ReleaseActCtx(IntPtr hActCtx);\n\n        [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]\n        public struct ACTCTX\n        {\n            public int cbSize;\n            public ActivationContextFlags dwFlags;\n            public string lpSource;\n            public ushort wProcessorArchitecture;\n            public ushort wLangId;\n            public string lpAssemblyDirectory;\n            public string lpResourceName;\n            public string lpApplicationName;\n            public IntPtr hModule;\n        }\n\n        [Flags]\n        public enum ActivationContextFlags : uint\n        {\n            ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x008,\n            ACTCTX_FLAG_APPLICATION_NAME_VALID = 0x020\n        }\n\n        public class ActivationContext : IDisposable\n        {\n            readonly IntPtr INVALID_HANDLE_VALUE = new(-1);\n            IntPtr activationContext = new(-1);\n            IntPtr activationContextCookie;\n\n            public ActivationContext(FileInfo manifestFile)\n            {\n                ArgumentNullException.ThrowIfNull(manifestFile, nameof(manifestFile));\n\n                var requestedActivationContext = new ACTCTX\n                {\n                    cbSize = Marshal.SizeOf<ACTCTX>(),\n                    lpSource = manifestFile.FullName\n                };\n\n                activationContext = CreateActCtxW(ref requestedActivationContext);\n                if (activationContext != INVALID_HANDLE_VALUE)\n                {\n                    if (!ActivateActCtx(activationContext, out activationContextCookie))\n                    {\n                        throw new Win32Exception(Marshal.GetLastWin32Error());\n                    }\n                }\n                else\n                {\n                    throw new Win32Exception(Marshal.GetLastWin32Error());\n                }\n            }\n\n            public void Dispose()\n            {\n                if (activationContextCookie != IntPtr.Zero)\n                {\n                    if (!DeactivateActCtx(dwFlags: 0, activationContextCookie))\n                    {\n                        throw new Win32Exception(Marshal.GetLastWin32Error());\n                    }\n\n                    activationContextCookie = IntPtr.Zero;\n                }\n\n                if (activationContext != INVALID_HANDLE_VALUE)\n                {\n                    ReleaseActCtx(activationContext);\n                    activationContext = INVALID_HANDLE_VALUE;\n                }\n            }\n        }\n    }\n#pragma warning restore IDE1006 // Naming Styles\n}"
  },
  {
    "path": "src/Sign.Core/Native/Ntdsapi.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Runtime.InteropServices;\n\nnamespace Sign.Core\n{\n    internal static class Ntdsapi\n    {\n        [method: DllImport(\"ntdsapi.dll\", EntryPoint = \"DsGetRdnW\", ExactSpelling = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]\n        [return: MarshalAs(UnmanagedType.Error)]\n        internal static extern int DsGetRdnW(\n            [param: In, Out, MarshalAs(UnmanagedType.SysInt)] ref IntPtr ppDN,\n            [param: In, Out, MarshalAs(UnmanagedType.U4)] ref uint pcDN,\n            [param: Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr ppKey,\n            [param: Out, MarshalAs(UnmanagedType.U4)] out uint pcKey,\n            [param: Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr ppVal,\n            [param: Out, MarshalAs(UnmanagedType.U4)] out uint pcVal);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Native/mansign2.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\n#define RUNTIME_TYPE_NETCORE\n\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.InteropServices;\nusing System.Runtime.Versioning;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Security.Cryptography.Xml;\nusing System.Text;\nusing System.Xml;\nusing _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;\n\n#nullable disable\n\nnamespace System.Deployment.Internal.CodeSigning\n{\n    internal static class Win32\n    {\n        //\n        // PInvoke dll's.\n        //\n        internal const String CRYPT32 = \"crypt32.dll\";\n        internal const String KERNEL32 = \"kernel32.dll\";\n#if (true)\n\n#if FEATURE_MAIN_CLR_MODULE_USES_CORE_NAME\n        internal const String MSCORWKS = \"coreclr.dll\";\n#elif USE_OLD_MSCORWKS_NAME // for updating devdiv toolset until it has clr.dll\n        internal const String MSCORWKS = \"mscorwks.dll\";\n#else //FEATURE_MAIN_CLR_MODULE_USES_CORE_NAME\n        internal const String MSCORWKS = \"clr.dll\";\n#endif //FEATURE_MAIN_CLR_MODULE_USES_CORE_NAME\n\n#else\n        internal const String MSCORWKS = \"isowhidbey.dll\";\n#endif\n        //\n        // Constants.\n        //\n        internal const int S_OK = unchecked((int)0x00000000);\n        internal const int NTE_BAD_KEY = unchecked((int)0x80090003);\n\n        // Trust errors.\n        internal const int TRUST_E_SYSTEM_ERROR = unchecked((int)0x80096001);\n        internal const int TRUST_E_NO_SIGNER_CERT = unchecked((int)0x80096002);\n        internal const int TRUST_E_COUNTER_SIGNER = unchecked((int)0x80096003);\n        internal const int TRUST_E_CERT_SIGNATURE = unchecked((int)0x80096004);\n        internal const int TRUST_E_TIME_STAMP = unchecked((int)0x80096005);\n        internal const int TRUST_E_BAD_DIGEST = unchecked((int)0x80096010);\n        internal const int TRUST_E_BASIC_CONSTRAINTS = unchecked((int)0x80096019);\n        internal const int TRUST_E_FINANCIAL_CRITERIA = unchecked((int)0x8009601E);\n        internal const int TRUST_E_PROVIDER_UNKNOWN = unchecked((int)0x800B0001);\n        internal const int TRUST_E_ACTION_UNKNOWN = unchecked((int)0x800B0002);\n        internal const int TRUST_E_SUBJECT_FORM_UNKNOWN = unchecked((int)0x800B0003);\n        internal const int TRUST_E_SUBJECT_NOT_TRUSTED = unchecked((int)0x800B0004);\n        internal const int TRUST_E_NOSIGNATURE = unchecked((int)0x800B0100);\n        internal const int CERT_E_UNTRUSTEDROOT = unchecked((int)0x800B0109);\n        internal const int TRUST_E_FAIL = unchecked((int)0x800B010B);\n        internal const int TRUST_E_EXPLICIT_DISTRUST = unchecked((int)0x800B0111);\n        internal const int CERT_E_CHAINING = unchecked((int)0x800B010A);\n\n        // Values for dwFlags of CertVerifyAuthenticodeLicense.\n        internal const int AXL_REVOCATION_NO_CHECK = unchecked((int)0x00000001);\n        internal const int AXL_REVOCATION_CHECK_END_CERT_ONLY = unchecked((int)0x00000002);\n        internal const int AXL_REVOCATION_CHECK_ENTIRE_CHAIN = unchecked((int)0x00000004);\n        internal const int AXL_URL_CACHE_ONLY_RETRIEVAL = unchecked((int)0x00000008);\n        internal const int AXL_LIFETIME_SIGNING = unchecked((int)0x00000010);\n        internal const int AXL_TRUST_MICROSOFT_ROOT_ONLY = unchecked((int)0x00000020);\n\n        // Wintrust Policy Flag\n        //  These are set during install and can be modified by the user\n        //  through various means.  The SETREG.EXE utility (found in the Authenticode\n        //  Tools Pack) will select/deselect each of them.\n        internal const int WTPF_IGNOREREVOKATION = (int)0x00000200;  // Do revocation check\n\n        // The default WinVerifyTrust Authenticode policy is to treat all time stamped\n        // signatures as being valid forever. This OID limits the valid lifetime of the\n        // signature to the lifetime of the certificate. This allows timestamped\n        // signatures to expire. Normally this OID will be used in conjunction with\n        // szOID_PKIX_KP_CODE_SIGNING to indicate new time stamp semantics should be\n        // used. Support for this OID was added in WXP.\n        internal const string szOID_KP_LIFETIME_SIGNING = \"1.3.6.1.4.1.311.10.3.13\";\n        internal const string szOID_RSA_signingTime = \"1.2.840.113549.1.9.5\";\n\n        //\n        // Structures.\n        //\n        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\n        internal struct CRYPT_DATA_BLOB\n        {\n            internal uint cbData;\n            internal IntPtr pbData;\n        }\n\n        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\n        internal struct AXL_SIGNER_INFO\n        {\n            internal uint cbSize;             // sizeof(AXL_SIGNER_INFO).\n            internal uint dwError;            // Error code.\n            internal uint algHash;            // Hash algorithm (ALG_ID).\n            internal IntPtr pwszHash;           // Hash.\n            internal IntPtr pwszDescription;    // Description.\n            internal IntPtr pwszDescriptionUrl; // Description URL.\n            internal IntPtr pChainContext;      // Signer's chain context.\n        }\n\n        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\n        internal struct AXL_TIMESTAMPER_INFO\n        {\n            internal uint cbSize;             // sizeof(AXL_TIMESTAMPER_INFO).\n            internal uint dwError;            // Error code.\n            internal uint algHash;            // Hash algorithm (ALG_ID).\n            internal _FILETIME ftTimestamp;        // Timestamp time.\n            internal IntPtr pChainContext;      // Timestamper's chain context.\n        }\n\n        //\n        // DllImport declarations.\n        //\n        [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        IntPtr GetProcessHeap();\n\n        [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        internal static extern\n        bool HeapFree(\n            [In] IntPtr hHeap,\n            [In] uint dwFlags,\n            [In] IntPtr lpMem);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int CertTimestampAuthenticodeLicense(\n            [In] ref CRYPT_DATA_BLOB pSignedLicenseBlob,\n            [In] string pwszTimestampURI,\n            [In, Out] ref CRYPT_DATA_BLOB pTimestampSignatureBlob);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int CertVerifyAuthenticodeLicense(\n            [In] ref CRYPT_DATA_BLOB pLicenseBlob,\n            [In] uint dwFlags,\n            [In, Out] ref AXL_SIGNER_INFO pSignerInfo,\n            [In, Out] ref AXL_TIMESTAMPER_INFO pTimestamperInfo);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int CertFreeAuthenticodeSignerInfo(\n            [In] ref AXL_SIGNER_INFO pSignerInfo);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int CertFreeAuthenticodeTimestamperInfo(\n            [In] ref AXL_TIMESTAMPER_INFO pTimestamperInfo);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int _AxlGetIssuerPublicKeyHash(\n            [In] IntPtr pCertContext,\n            [In, Out] ref IntPtr ppwszPublicKeyHash);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int _AxlRSAKeyValueToPublicKeyToken(\n            [In] ref CRYPT_DATA_BLOB pModulusBlob,\n            [In] ref CRYPT_DATA_BLOB pExponentBlob,\n            [In, Out] ref IntPtr ppwszPublicKeyToken);\n\n        [DllImport(MSCORWKS, CharSet = CharSet.Auto, SetLastError = true)]\n        internal static extern\n        int _AxlPublicKeyBlobToPublicKeyToken(\n            [In] ref CRYPT_DATA_BLOB pCspPublicKeyBlob,\n            [In, Out] ref IntPtr ppwszPublicKeyToken);\n\n        // RFC3161 timestamp support\n\n        // hash algorithm OIDs\n        internal const string szOID_NIST_sha256 = \"2.16.840.1.101.3.4.2.1\";\n\n        [StructLayout(LayoutKind.Sequential)]\n        internal struct CRYPT_TIMESTAMP_CONTEXT\n        {\n            internal uint cbEncoded;      // DWORD->unsigned int\n            internal IntPtr pbEncoded;      // BYTE*\n            internal IntPtr pTimeStamp;     // PCRYPT_TIMESTAMP_INFO->_CRYPT_TIMESTAMP_INFO*\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        internal struct CRYPTOAPI_BLOB\n        {\n            internal uint cbData;\n            internal IntPtr pbData;\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        internal struct CRYPT_TIMESTAMP_PARA\n        {\n            internal IntPtr pszTSAPolicyId;\n            internal bool fRequestCerts;\n            internal CRYPTOAPI_BLOB Nonce;\n            internal int cExtension;\n            internal IntPtr rgExtension;\n        }\n\n        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n        [DllImport(CRYPT32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        internal static extern\n        bool CryptRetrieveTimeStamp(\n            [In][MarshalAs(UnmanagedType.LPWStr)] string wszUrl,\n            [In] uint dwRetrievalFlags,\n            [In] int dwTimeout,\n            [In][MarshalAs(UnmanagedType.LPStr)] string pszHashId,\n            [In, Out] ref CRYPT_TIMESTAMP_PARA pPara,\n            [In] byte[] pbData,\n            [In] int cbData,\n            [In, Out] ref IntPtr ppTsContext,\n            [In, Out] ref IntPtr ppTsSigner,\n            [In, Out] ref IntPtr phStore);\n\n        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n        [DllImport(CRYPT32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]\n        internal static extern bool CertFreeCertificateContext(IntPtr pCertContext);\n\n        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n        [DllImport(CRYPT32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]\n        internal static extern bool CertCloseStore(IntPtr pCertContext, int dwFlags);\n\n        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n        [DllImport(CRYPT32, CallingConvention = CallingConvention.Winapi)]\n        internal static extern void CryptMemFree(IntPtr pv);\n    }\n\n    internal class ManifestSignedXml2 : SignedXml\n    {\n        private bool _verify = false;\n        private const string Sha256SignatureMethodUri = @\"http://www.w3.org/2000/09/xmldsig#rsa-sha256\";\n        private const string Sha256DigestMethod = @\"http://www.w3.org/2000/09/xmldsig#sha256\";\n\n        internal ManifestSignedXml2()\n            : base()\n        {\n            init();\n        }\n        internal ManifestSignedXml2(XmlElement elem)\n            : base(elem)\n        {\n            init();\n        }\n        internal ManifestSignedXml2(XmlDocument document)\n            : base(document)\n        {\n            init();\n        }\n\n        internal ManifestSignedXml2(XmlDocument document, bool verify)\n            : base(document)\n        {\n            _verify = verify;\n            init();\n        }\n\n        private void init()\n        {\n            CryptoConfig.AddAlgorithm(typeof(Sign.Core.RSAPKCS1SHA256SignatureDescription),\n                               Sha256SignatureMethodUri);\n\n#if RUNTIME_TYPE_NETCORE\n#pragma warning disable SYSLIB0021 // Type or member is obsolete\n            CryptoConfig.AddAlgorithm(typeof(SHA256Managed),\n                               Sha256DigestMethod);\n#pragma warning restore SYSLIB0021 // Type or member is obsolete\n#else\n            CryptoConfig.AddAlgorithm(typeof(System.Security.Cryptography.SHA256Cng),\n                               Sha256DigestMethod);\n#endif\n        }\n\n        public override XmlElement GetIdElement(XmlDocument document, string idValue)\n        {\n            // We only care about Id references inside of the KeyInfo section\n            if (_verify)\n            {\n                return base.GetIdElement(document, idValue);\n            }\n\n            KeyInfo keyInfo = this.KeyInfo;\n            if (keyInfo.Id != idValue)\n            {\n                return null;\n            }\n\n            return keyInfo.GetXml();\n        }\n    }\n\n    [SupportedOSPlatform(\"windows\")]\n    internal class SignedCmiManifest2\n    {\n        private XmlDocument _manifestDom = null;\n        private CmiStrongNameSignerInfo _strongNameSignerInfo = null;\n        private CmiAuthenticodeSignerInfo _authenticodeSignerInfo = null;\n\n        private const string Sha256SignatureMethodUri = @\"http://www.w3.org/2000/09/xmldsig#rsa-sha256\";\n        private const string Sha256DigestMethod = @\"http://www.w3.org/2000/09/xmldsig#sha256\";\n\n        private SignedCmiManifest2() { }\n\n        internal SignedCmiManifest2(XmlDocument manifestDom)\n        {\n            _manifestDom = manifestDom ?? throw new ArgumentNullException(nameof(manifestDom));\n        }\n\n        internal void Sign(CmiManifestSigner2 signer)\n        {\n            Sign(signer, null);\n        }\n\n        internal void Sign(CmiManifestSigner2 signer, string timeStampUrl, bool disallowMansignTimestampFallback = false)\n        {\n            // Reset signer infos.\n            _strongNameSignerInfo = null;\n            _authenticodeSignerInfo = null;\n\n            // Signer cannot be null.\n            if (signer == null || signer.StrongNameKey == null)\n            {\n                throw new ArgumentNullException(nameof(signer));\n            }\n\n            // Remove existing SN signature.\n            RemoveExistingSignature(_manifestDom);\n\n            // Replace public key token in assemblyIdentity if requested.\n            if ((signer.Flag & CmiManifestSignerFlag.DontReplacePublicKeyToken) == 0)\n            {\n                ReplacePublicKeyToken(_manifestDom, signer.StrongNameKey);\n            }\n\n            // No cert means don't Authenticode sign and timestamp.\n            XmlDocument licenseDom = null;\n            if (signer.Certificate != null)\n            {\n                // Yes. We will Authenticode sign, so first insert <publisherIdentity />\n                // element, if necessary.\n                InsertPublisherIdentity(_manifestDom, signer.Certificate);\n\n                // Now create the license DOM, and then sign it.\n                licenseDom = CreateLicenseDom(signer, ExtractPrincipalFromManifest(), ComputeHashFromManifest(_manifestDom));\n                AuthenticodeSignLicenseDom(licenseDom, signer, timeStampUrl, disallowMansignTimestampFallback);\n            }\n            StrongNameSignManifestDom(_manifestDom, licenseDom, signer);\n        }\n\n        internal CmiStrongNameSignerInfo StrongNameSignerInfo\n        {\n            get\n            {\n                return _strongNameSignerInfo;\n            }\n        }\n\n        internal CmiAuthenticodeSignerInfo AuthenticodeSignerInfo\n        {\n            get\n            {\n                return _authenticodeSignerInfo;\n            }\n        }\n\n        //\n        // Privates.\n        //\n        private XmlElement ExtractPrincipalFromManifest()\n        {\n            XmlNamespaceManager nsm = new XmlNamespaceManager(_manifestDom.NameTable);\n            nsm.AddNamespace(\"asm\", AssemblyNamespaceUri);\n            XmlNode assemblyIdentityNode = _manifestDom.SelectSingleNode(\"asm:assembly/asm:assemblyIdentity\", nsm);\n            if (assemblyIdentityNode == null)\n            {\n                throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN);\n            }\n\n            return assemblyIdentityNode as XmlElement;\n        }\n\n        //\n        // Statics.\n        //\n        private static void InsertPublisherIdentity(XmlDocument manifestDom, X509Certificate2 signerCert)\n        {\n            XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable);\n            nsm.AddNamespace(\"asm\", AssemblyNamespaceUri);\n            nsm.AddNamespace(\"asm2\", AssemblyV2NamespaceUri);\n            nsm.AddNamespace(\"ds\", SignedXml.XmlDsigNamespaceUrl);\n\n            XmlElement assembly = manifestDom.SelectSingleNode(\"asm:assembly\", nsm) as XmlElement;\n            XmlElement assemblyIdentity = manifestDom.SelectSingleNode(\"asm:assembly/asm:assemblyIdentity\", nsm) as XmlElement;\n            if (assemblyIdentity == null)\n            {\n                throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN);\n            }\n\n            // Reuse existing node if exists\n            XmlElement publisherIdentity = manifestDom.SelectSingleNode(\"asm:assembly/asm2:publisherIdentity\", nsm) as XmlElement;\n            if (publisherIdentity == null)\n            {\n                // create new if not exist\n                publisherIdentity = manifestDom.CreateElement(\"publisherIdentity\", AssemblyV2NamespaceUri);\n            }\n            // Get the issuer's public key blob hash.\n            IntPtr pIssuerKeyHash = new IntPtr();\n            int hr = Win32._AxlGetIssuerPublicKeyHash(signerCert.Handle, ref pIssuerKeyHash);\n            if (hr != Win32.S_OK)\n            {\n                throw new CryptographicException(hr);\n            }\n\n            string issuerKeyHash = Marshal.PtrToStringUni(pIssuerKeyHash);\n            Win32.HeapFree(Win32.GetProcessHeap(), 0, pIssuerKeyHash);\n\n            publisherIdentity.SetAttribute(\"name\", signerCert.SubjectName.Name);\n            publisherIdentity.SetAttribute(\"issuerKeyHash\", issuerKeyHash);\n\n            XmlElement signature = manifestDom.SelectSingleNode(\"asm:assembly/ds:Signature\", nsm) as XmlElement;\n            if (signature != null)\n            {\n                assembly.InsertBefore(publisherIdentity, signature);\n            }\n            else\n            {\n                assembly.AppendChild(publisherIdentity);\n            }\n        }\n\n        private static void RemoveExistingSignature(XmlDocument manifestDom)\n        {\n            XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable);\n            nsm.AddNamespace(\"asm\", AssemblyNamespaceUri);\n            nsm.AddNamespace(\"ds\", SignedXml.XmlDsigNamespaceUrl);\n            XmlNode signatureNode = manifestDom.SelectSingleNode(\"asm:assembly/ds:Signature\", nsm);\n            if (signatureNode != null)\n            {\n                signatureNode.ParentNode.RemoveChild(signatureNode);\n            }\n        }\n\n        /// <summary>\n        /// The reason you need provider type 24, is because that’s the only RSA provider type that supports SHA-2 operations.   (For instance, PROV_RSA_FULL does not support SHA-2).\n        /// As for official guidance – I’m not sure of any.    For workarounds though, if you’re using the Microsoft software CSPs, they share the underlying key store.  You can get the key container name from your RSA object, then open up a new RSA object with the same key container name but with PROV_RSA_AES.   At that point, you should be able to use SHA-2 algorithms.\n        /// </summary>\n        /// <param name=\"oldCsp\"></param>\n        /// \n        /// <returns></returns>\n        internal static RSACryptoServiceProvider GetFixedRSACryptoServiceProvider(RSACryptoServiceProvider oldCsp)\n        {\n            // 3rd party crypto providers in general don't need to be forcefully upgraded.\n            // This not an ideal way to check for that but is the best we have available.\n            if (!oldCsp.CspKeyContainerInfo.ProviderName.StartsWith(\"Microsoft\", StringComparison.Ordinal))\n            {\n                return oldCsp;\n            }\n\n            const int PROV_RSA_AES = 24;    // CryptoApi provider type for an RSA provider supporting sha-256 digital signatures\n            CspParameters csp = new CspParameters();\n            csp.ProviderType = PROV_RSA_AES;\n            csp.KeyContainerName = oldCsp.CspKeyContainerInfo.KeyContainerName;\n            csp.KeyNumber = (int)oldCsp.CspKeyContainerInfo.KeyNumber;\n            if (oldCsp.CspKeyContainerInfo.MachineKeyStore)\n            {\n                csp.Flags = CspProviderFlags.UseMachineKeyStore;\n            }\n            RSACryptoServiceProvider fixedRsa = new RSACryptoServiceProvider(csp);\n\n            return fixedRsa;\n        }\n\n        private static void ReplacePublicKeyToken(XmlDocument manifestDom, AsymmetricAlgorithm snKey)\n        {\n            // Make sure we can find the publicKeyToken attribute.\n            XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable);\n            nsm.AddNamespace(\"asm\", AssemblyNamespaceUri);\n            XmlElement assemblyIdentity = manifestDom.SelectSingleNode(\"asm:assembly/asm:assemblyIdentity\", nsm) as XmlElement;\n            if (assemblyIdentity == null)\n            {\n                throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN);\n            }\n\n            if (!assemblyIdentity.HasAttribute(\"publicKeyToken\"))\n            {\n                throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN);\n            }\n\n            byte[] cspPublicKeyBlob;\n\n            if (snKey is RSACryptoServiceProvider rsacsp)\n            {\n                cspPublicKeyBlob = (GetFixedRSACryptoServiceProvider(rsacsp)).ExportCspBlob(false);\n                if (cspPublicKeyBlob == null || cspPublicKeyBlob.Length == 0)\n                {\n                    throw new CryptographicException(Win32.NTE_BAD_KEY);\n                }\n            }\n            else\n            {\n                using (RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider())\n                {\n                    rsaCsp.ImportParameters(((RSA)snKey).ExportParameters(false));\n                    cspPublicKeyBlob = rsaCsp.ExportCspBlob(false);\n                }\n            }\n            // Now compute the public key token.\n            unsafe\n            {\n                fixed (byte* pbPublicKeyBlob = cspPublicKeyBlob)\n                {\n                    Win32.CRYPT_DATA_BLOB publicKeyBlob = new Win32.CRYPT_DATA_BLOB();\n                    publicKeyBlob.cbData = (uint)cspPublicKeyBlob.Length;\n                    publicKeyBlob.pbData = new IntPtr(pbPublicKeyBlob);\n                    IntPtr pPublicKeyToken = new IntPtr();\n\n                    int hr = Win32._AxlPublicKeyBlobToPublicKeyToken(ref publicKeyBlob, ref pPublicKeyToken);\n                    if (hr != Win32.S_OK)\n                    {\n                        throw new CryptographicException(hr);\n                    }\n\n                    string publicKeyToken = Marshal.PtrToStringUni(pPublicKeyToken);\n                    Win32.HeapFree(Win32.GetProcessHeap(), 0, pPublicKeyToken);\n\n                    assemblyIdentity.SetAttribute(\"publicKeyToken\", publicKeyToken);\n                }\n            }\n        }\n\n        private static byte[] ComputeHashFromManifest(XmlDocument manifestDom)\n        {\n#if (true) // BUGBUG: Remove before RTM when old format support is no longer needed.\n            return ComputeHashFromManifest(manifestDom, false);\n        }\n\n        private static byte[] ComputeHashFromManifest(XmlDocument manifestDom, bool oldFormat)\n        {\n            if (oldFormat)\n            {\n                XmlDsigExcC14NTransform exc = new XmlDsigExcC14NTransform();\n                exc.LoadInput(manifestDom);\n\n#pragma warning disable SA1111, SA1009 // Closing parenthesis should be on line of last parameter\n                using (SHA256 sha2 = SHA256.Create(\n#if FEATURE_CRYPTOGRAPHIC_FACTORY_ALGORITHM_NAMES\n                    \"System.Security.Cryptography.SHA256CryptoServiceProvider\"\n#endif\n                    ))\n#pragma warning restore SA1111, SA1009 // Closing parenthesis should be on line of last parameter\n                {\n                    byte[] hash = sha2.ComputeHash(exc.GetOutput() as MemoryStream);\n                    if (hash == null)\n                    {\n                        throw new CryptographicException(Win32.TRUST_E_BAD_DIGEST);\n                    }\n\n                    return hash;\n                }\n            }\n            else\n            {\n#endif\n                // Since the DOM given to us is not guaranteed to be normalized,\n                // we need to normalize it ourselves. Also, we always preserve\n                // white space as Fusion XML engine always preserve white space.\n                XmlDocument normalizedDom = new XmlDocument();\n                normalizedDom.PreserveWhitespace = true;\n\n                // Normalize the document\n                using (TextReader stringReader = new StringReader(manifestDom.OuterXml))\n                {\n                    XmlReaderSettings settings = new XmlReaderSettings();\n                    settings.DtdProcessing = DtdProcessing.Parse;\n                    XmlReader reader = XmlReader.Create(stringReader, settings, manifestDom.BaseURI);\n                    normalizedDom.Load(reader);\n                }\n\n                XmlDsigExcC14NTransform exc = new XmlDsigExcC14NTransform();\n                exc.LoadInput(normalizedDom);\n\n#pragma warning disable SA1111, SA1009 // Closing parenthesis should be on line of last parameter\n                using (SHA256 sha2 = SHA256.Create(\n#if FEATURE_CRYPTOGRAPHIC_FACTORY_ALGORITHM_NAMES\n                    \"System.Security.Cryptography.SHA256CryptoServiceProvider\"\n#endif\n                    ))\n#pragma warning restore SA1111, SA1009 // Closing parenthesis should be on line of last parameter\n                {\n                    byte[] hash = sha2.ComputeHash(exc.GetOutput() as MemoryStream);\n                    if (hash == null)\n                    {\n                        throw new CryptographicException(Win32.TRUST_E_BAD_DIGEST);\n                    }\n\n                    return hash;\n                }\n#if (true) // BUGBUG: Remove before RTM when old format support is no longer needed.\n            }\n#endif\n        }\n\n        private const string AssemblyNamespaceUri = \"urn:schemas-microsoft-com:asm.v1\";\n        private const string AssemblyV2NamespaceUri = \"urn:schemas-microsoft-com:asm.v2\";\n        private const string MSRelNamespaceUri = \"http://schemas.microsoft.com/windows/rel/2005/reldata\";\n        private const string LicenseNamespaceUri = \"urn:mpeg:mpeg21:2003:01-REL-R-NS\";\n        private const string AuthenticodeNamespaceUri = \"http://schemas.microsoft.com/windows/pki/2005/Authenticode\";\n        private const string licenseTemplate = \"<r:license xmlns:r=\\\"\" + LicenseNamespaceUri + \"\\\" xmlns:as=\\\"\" + AuthenticodeNamespaceUri + \"\\\">\" +\n                                                    @\"<r:grant>\" +\n                                                    @\"<as:ManifestInformation>\" +\n                                                    @\"<as:assemblyIdentity />\" +\n                                                    @\"</as:ManifestInformation>\" +\n                                                    @\"<as:SignedBy/>\" +\n                                                    @\"<as:AuthenticodePublisher>\" +\n                                                    @\"<as:X509SubjectName>CN=dummy</as:X509SubjectName>\" +\n                                                    @\"</as:AuthenticodePublisher>\" +\n                                                    @\"</r:grant><r:issuer></r:issuer></r:license>\";\n\n        [SuppressMessage(\"Microsoft.Security.Xml\", \"CA3057: DoNotUseLoadXml.\", Justification = \"Suppressed since the xml being loaded is a constant defined in this file.\")]\n        private static XmlDocument CreateLicenseDom(CmiManifestSigner2 signer, XmlElement principal, byte[] hash)\n        {\n            XmlDocument licenseDom = new XmlDocument();\n            licenseDom.PreserveWhitespace = true;\n            // CA3057: DoNotUseLoadXml. Suppressed since the xml being loaded is a constant defined in this file.\n            licenseDom.LoadXml(licenseTemplate);\n            XmlNamespaceManager nsm = new XmlNamespaceManager(licenseDom.NameTable);\n            nsm.AddNamespace(\"r\", LicenseNamespaceUri);\n            nsm.AddNamespace(\"as\", AuthenticodeNamespaceUri);\n            XmlElement assemblyIdentityNode = licenseDom.SelectSingleNode(\"r:license/r:grant/as:ManifestInformation/as:assemblyIdentity\", nsm) as XmlElement;\n            assemblyIdentityNode.RemoveAllAttributes();\n            foreach (XmlAttribute attribute in principal.Attributes)\n            {\n                assemblyIdentityNode.SetAttribute(attribute.Name, attribute.Value);\n            }\n\n            XmlElement manifestInformationNode = licenseDom.SelectSingleNode(\"r:license/r:grant/as:ManifestInformation\", nsm) as XmlElement;\n\n            manifestInformationNode.SetAttribute(\"Hash\", hash.Length == 0 ? \"\" : BytesToHexString(hash, 0, hash.Length));\n            manifestInformationNode.SetAttribute(\"Description\", signer.Description ?? \"\");\n            manifestInformationNode.SetAttribute(\"Url\", signer.DescriptionUrl ?? \"\");\n\n            XmlElement authenticodePublisherNode = licenseDom.SelectSingleNode(\"r:license/r:grant/as:AuthenticodePublisher/as:X509SubjectName\", nsm) as XmlElement;\n            authenticodePublisherNode.InnerText = signer.Certificate.SubjectName.Name;\n\n            return licenseDom;\n        }\n\n        private static void AuthenticodeSignLicenseDom(XmlDocument licenseDom, CmiManifestSigner2 signer, string timeStampUrl, bool disallowMansignTimestampFallback)\n        {\n            // Make sure it is RSA, as this is the only one Fusion will support.\n            RSA rsaPrivateKey = signer.Certificate.HasPrivateKey\n                ? signer.Certificate.GetRSAPrivateKey()\n                : signer.StrongNameKey as RSA;\n\n            if (rsaPrivateKey == null)\n            {\n                throw new NotSupportedException();\n            }\n\n            // Setup up XMLDSIG engine.\n            ManifestSignedXml2 signedXml = new ManifestSignedXml2(licenseDom);\n            // only needs to change the provider type when RSACryptoServiceProvider is used\n            var rsaCsp = rsaPrivateKey is RSACryptoServiceProvider ?\n                            GetFixedRSACryptoServiceProvider(rsaPrivateKey as RSACryptoServiceProvider) : rsaPrivateKey;\n            signedXml.SigningKey = rsaCsp;\n            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;\n            signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri;\n\n            // Add the key information.\n            signedXml.KeyInfo.AddClause(new RSAKeyValue(rsaCsp));\n            signedXml.KeyInfo.AddClause(new KeyInfoX509Data(signer.Certificate, signer.IncludeOption));\n\n            // Add the enveloped reference.\n            Reference reference = new Reference();\n            reference.Uri = \"\";\n            reference.DigestMethod = Sha256DigestMethod;\n\n            // Add an enveloped and an Exc-C14N transform.\n            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());\n#if (false) // BUGBUG: LTA transform complaining about issuer node not found.\n            reference.AddTransform(new XmlLicenseTransform()); \n#endif\n            reference.AddTransform(new XmlDsigExcC14NTransform());\n\n            // Add the reference.\n            signedXml.AddReference(reference);\n\n            // Compute the signature.\n            signedXml.ComputeSignature();\n\n            // Get the XML representation\n            XmlElement xmlDigitalSignature = signedXml.GetXml();\n            xmlDigitalSignature.SetAttribute(\"Id\", \"AuthenticodeSignature\");\n\n            // Insert the signature node under the issuer element.\n            XmlNamespaceManager nsm = new XmlNamespaceManager(licenseDom.NameTable);\n            nsm.AddNamespace(\"r\", LicenseNamespaceUri);\n            XmlElement issuerNode = licenseDom.SelectSingleNode(\"r:license/r:issuer\", nsm) as XmlElement;\n            issuerNode.AppendChild(licenseDom.ImportNode(xmlDigitalSignature, true));\n\n            // Time stamp it if requested.\n            if (!string.IsNullOrEmpty(timeStampUrl))\n            {\n                TimestampSignedLicenseDom(licenseDom, timeStampUrl, disallowMansignTimestampFallback);\n            }\n\n            // Wrap it inside a RelData element.\n            licenseDom.DocumentElement.ParentNode.InnerXml = \"<msrel:RelData xmlns:msrel=\\\"\" +\n                                                             MSRelNamespaceUri + \"\\\">\" +\n                                                             licenseDom.OuterXml + \"</msrel:RelData>\";\n        }\n\n        //\n        // ObtainRFC3161Timestamp\n        //\n        // This function is from mage.exe in .NET FX and is used to implement RFC 3161 timestamping.\n        //\n        private static string ObtainRFC3161Timestamp(string timeStampUrl, string signatureValue)\n        {\n            byte[] sigValueBytes = Convert.FromBase64String(signatureValue);\n            string timestamp = String.Empty;\n\n            string algId = Win32.szOID_NIST_sha256;\n\n            unsafe\n            {\n                IntPtr ppTsContext = IntPtr.Zero;\n                IntPtr ppTsSigner = IntPtr.Zero;\n                IntPtr phStore = IntPtr.Zero;\n\n                try\n                {\n                    byte[] nonce = new byte[24];\n\n                    using (RandomNumberGenerator rng = RandomNumberGenerator.Create())\n                    {\n                        rng.GetBytes(nonce);\n                    }\n\n                    Win32.CRYPT_TIMESTAMP_PARA para = new Win32.CRYPT_TIMESTAMP_PARA()\n                    {\n                        fRequestCerts = true,\n                        pszTSAPolicyId = IntPtr.Zero,\n                    };\n\n                    fixed (byte* pbNonce = nonce)\n                    {\n                        para.Nonce.cbData = (uint)nonce.Length;\n                        para.Nonce.pbData = (IntPtr)pbNonce;\n\n                        if (!Win32.CryptRetrieveTimeStamp(\n                            timeStampUrl,\n                            0,\n                            60 * 1000,  // 1 minute timeout\n                            algId,\n                            ref para,\n                            sigValueBytes,\n                            sigValueBytes.Length,\n                            ref ppTsContext,\n                            ref ppTsSigner,\n                            ref phStore))\n                        {\n                            throw new CryptographicException(Marshal.GetLastWin32Error());\n                        }\n                    }\n\n                    var timestampContext = (Win32.CRYPT_TIMESTAMP_CONTEXT)Marshal.PtrToStructure(ppTsContext, typeof(Win32.CRYPT_TIMESTAMP_CONTEXT));\n                    byte[] encodedBytes = new byte[(int)timestampContext.cbEncoded];\n                    Marshal.Copy(timestampContext.pbEncoded, encodedBytes, 0, (int)timestampContext.cbEncoded);\n                    timestamp = Convert.ToBase64String(encodedBytes);\n                }\n                finally\n                {\n                    if (ppTsContext != IntPtr.Zero)\n                    {\n                        Win32.CryptMemFree(ppTsContext);\n                    }\n\n                    if (ppTsSigner != IntPtr.Zero)\n                    {\n                        Win32.CertFreeCertificateContext(ppTsSigner);\n                    }\n\n                    if (phStore != IntPtr.Zero)\n                    {\n                        Win32.CertCloseStore(phStore, 0);\n                    }\n                }\n            }\n\n            return timestamp;\n        }\n\n        private static void TimestampSignedLicenseDom(XmlDocument licenseDom, string timeStampUrl, bool disallowMansignTimestampFallback)\n        {\n            XmlNamespaceManager nsm = new XmlNamespaceManager(licenseDom.NameTable);\n            nsm.AddNamespace(\"r\", LicenseNamespaceUri);\n            nsm.AddNamespace(\"ds\", SignedXml.XmlDsigNamespaceUrl);\n            nsm.AddNamespace(\"as\", AuthenticodeNamespaceUri);\n\n            string timestamp = String.Empty;\n\n            try\n            {\n                // Try RFC3161 first\n                XmlElement signatureValueNode = licenseDom.SelectSingleNode(\"r:license/r:issuer/ds:Signature/ds:SignatureValue\", nsm) as XmlElement;\n                string signatureValue = signatureValueNode.InnerText;\n                timestamp = ObtainRFC3161Timestamp(timeStampUrl, signatureValue);\n            }\n            // Catch CryptographicException to ensure fallback to old code (non-RFC3161)\n            catch (CryptographicException)\n            {\n                if (disallowMansignTimestampFallback)\n                {\n                    throw;\n                }\n                else\n                {\n                    Win32.CRYPT_DATA_BLOB timestampBlob = new Win32.CRYPT_DATA_BLOB();\n\n                    byte[] licenseXml = Encoding.UTF8.GetBytes(licenseDom.OuterXml);\n\n                    unsafe\n                    {\n                        fixed (byte* pbLicense = licenseXml)\n                        {\n                            Win32.CRYPT_DATA_BLOB licenseBlob = new Win32.CRYPT_DATA_BLOB();\n                            IntPtr pvLicense = new IntPtr(pbLicense);\n                            licenseBlob.cbData = (uint)licenseXml.Length;\n                            licenseBlob.pbData = pvLicense;\n\n                            int hr = Win32.CertTimestampAuthenticodeLicense(ref licenseBlob, timeStampUrl, ref timestampBlob);\n                            if (hr != Win32.S_OK)\n                            {\n                                throw new CryptographicException(hr);\n                            }\n                        }\n                    }\n\n                    byte[] timestampSignature = new byte[timestampBlob.cbData];\n                    Marshal.Copy(timestampBlob.pbData, timestampSignature, 0, timestampSignature.Length);\n                    Win32.HeapFree(Win32.GetProcessHeap(), 0, timestampBlob.pbData);\n                    timestamp = Encoding.UTF8.GetString(timestampSignature);\n                }\n            }\n\n            XmlElement asTimestamp = licenseDom.CreateElement(\"as\", \"Timestamp\", AuthenticodeNamespaceUri);\n            asTimestamp.InnerText = timestamp;\n\n            XmlElement dsObject = licenseDom.CreateElement(\"Object\", SignedXml.XmlDsigNamespaceUrl);\n            dsObject.AppendChild(asTimestamp);\n\n            XmlElement signatureNode = licenseDom.SelectSingleNode(\"r:license/r:issuer/ds:Signature\", nsm) as XmlElement;\n            signatureNode.AppendChild(dsObject);\n        }\n\n        private static void StrongNameSignManifestDom(XmlDocument manifestDom, XmlDocument licenseDom, CmiManifestSigner2 signer)\n        {\n            RSA snKey = signer.StrongNameKey as RSA;\n\n            // Make sure it is RSA, as this is the only one Fusion will support.\n            if (snKey == null)\n            {\n                throw new NotSupportedException();\n            }\n\n            // Setup namespace manager.\n            XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable);\n            nsm.AddNamespace(\"asm\", AssemblyNamespaceUri);\n\n            // Get to root element.\n            XmlElement signatureParent = manifestDom.SelectSingleNode(\"asm:assembly\", nsm) as XmlElement;\n            if (signatureParent == null)\n            {\n                throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN);\n            }\n\n            // Setup up XMLDSIG engine.\n            ManifestSignedXml2 signedXml = new ManifestSignedXml2(signatureParent);\n            if (signer.StrongNameKey is RSACryptoServiceProvider rsacsp)\n            {\n                signedXml.SigningKey = GetFixedRSACryptoServiceProvider(rsacsp);\n            }\n            else\n            {\n                signedXml.SigningKey = signer.StrongNameKey;\n            }\n            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;\n            signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri;\n\n            // Add the key information.\n            signedXml.KeyInfo.AddClause(new RSAKeyValue(snKey));\n            if (licenseDom != null)\n            {\n                signedXml.KeyInfo.AddClause(new KeyInfoNode(licenseDom.DocumentElement));\n            }\n            signedXml.KeyInfo.Id = \"StrongNameKeyInfo\";\n\n            // Add the enveloped reference.\n            Reference enveloped = new Reference();\n            enveloped.Uri = \"\";\n            enveloped.DigestMethod = Sha256DigestMethod;\n\n            // Add an enveloped then Exc-C14N transform.\n            enveloped.AddTransform(new XmlDsigEnvelopedSignatureTransform());\n            enveloped.AddTransform(new XmlDsigExcC14NTransform());\n            signedXml.AddReference(enveloped);\n\n#if (false) // DSIE: New format does not sign KeyInfo.\n            // Add the key info reference.\n            Reference strongNameKeyInfo = new Reference();\n            strongNameKeyInfo.Uri = \"#StrongNameKeyInfo\";\n            strongNameKeyInfo.AddTransform(new XmlDsigExcC14NTransform());\n            signedXml.AddReference(strongNameKeyInfo);\n#endif\n            // Compute the signature.\n            signedXml.ComputeSignature();\n\n            // Get the XML representation\n            XmlElement xmlDigitalSignature = signedXml.GetXml();\n            xmlDigitalSignature.SetAttribute(\"Id\", \"StrongNameSignature\");\n\n            // Insert the signature now.\n            signatureParent.AppendChild(xmlDigitalSignature);\n        }\n        private static readonly char[] s_hexValues = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\n        private static string BytesToHexString(byte[] array, int start, int end)\n        {\n            string result = null;\n            if (array != null)\n            {\n                char[] hexOrder = new char[(end - start) * 2];\n                int i = end;\n                int digit, j = 0;\n                while (i-- > start)\n                {\n                    digit = (array[i] & 0xf0) >> 4;\n                    hexOrder[j++] = s_hexValues[digit];\n                    digit = (array[i] & 0x0f);\n                    hexOrder[j++] = s_hexValues[digit];\n                }\n                result = new String(hexOrder);\n            }\n            return result;\n        }\n    }\n\n    [Flags]\n    internal enum CmiManifestSignerFlag\n    {\n        None = 0x00000000,\n        DontReplacePublicKeyToken = 0x00000001\n    }\n\n    [Flags]\n    internal enum CmiManifestVerifyFlags\n    {\n        None = 0x00000000,\n        RevocationNoCheck = 0x00000001,\n        RevocationCheckEndCertOnly = 0x00000002,\n        RevocationCheckEntireChain = 0x00000004,\n        UrlCacheOnlyRetrieval = 0x00000008,\n        LifetimeSigning = 0x00000010,\n        TrustMicrosoftRootOnly = 0x00000020,\n        StrongNameOnly = 0x00010000\n    }\n\n    internal class CmiManifestSigner2\n    {\n        private AsymmetricAlgorithm _strongNameKey;\n        private X509Certificate2 _certificate;\n        private string _description;\n        private string _url;\n        private X509Certificate2Collection _certificates;\n        private X509IncludeOption _includeOption;\n        private CmiManifestSignerFlag _signerFlag;\n        private bool _useSha256 = true;\n\n        private CmiManifestSigner2() { }\n\n        internal CmiManifestSigner2(AsymmetricAlgorithm strongNameKey) :\n            this(strongNameKey, null)\n        { }\n\n        internal CmiManifestSigner2(AsymmetricAlgorithm strongNameKey, X509Certificate2 certificate)\n        {\n            if (strongNameKey == null)\n            {\n                throw new ArgumentNullException(nameof(strongNameKey));\n            }\n\n#if (true) // BUGBUG: Fusion only supports RSA. Do we throw if not RSA???\n            RSA rsa = strongNameKey as RSA;\n            if (rsa == null)\n            {\n                throw new ArgumentNullException(nameof(strongNameKey));\n            }\n#endif\n            _strongNameKey = strongNameKey;\n            _certificate = certificate;\n            _certificates = new X509Certificate2Collection();\n            _includeOption = X509IncludeOption.ExcludeRoot;\n            _signerFlag = CmiManifestSignerFlag.None;\n        }\n\n        internal bool UseSha256\n        {\n            get\n            {\n                return _useSha256;\n            }\n        }\n\n        internal AsymmetricAlgorithm StrongNameKey\n        {\n            get\n            {\n                return _strongNameKey;\n            }\n        }\n\n        internal X509Certificate2 Certificate\n        {\n            get\n            {\n                return _certificate;\n            }\n        }\n\n        internal string Description\n        {\n            get\n            {\n                return _description;\n            }\n            set\n            {\n                _description = value;\n            }\n        }\n\n        internal string DescriptionUrl\n        {\n            get\n            {\n                return _url;\n            }\n            set\n            {\n                _url = value;\n            }\n        }\n\n        internal X509Certificate2Collection ExtraStore\n        {\n            get\n            {\n                return _certificates;\n            }\n        }\n\n        internal X509IncludeOption IncludeOption\n        {\n            get\n            {\n                return _includeOption;\n            }\n            set\n            {\n                if (value < X509IncludeOption.None || value > X509IncludeOption.WholeChain)\n                {\n                    throw new ArgumentException(\"value\");\n                }\n\n                if (_includeOption == X509IncludeOption.None)\n                {\n                    throw new NotSupportedException();\n                }\n\n                _includeOption = value;\n            }\n        }\n\n        internal CmiManifestSignerFlag Flag\n        {\n            get\n            {\n                return _signerFlag;\n            }\n            set\n            {\n                unchecked\n                {\n                    if ((value & ((CmiManifestSignerFlag)~CimManifestSignerFlagMask)) != 0)\n                    {\n                        throw new ArgumentException(\"value\");\n                    }\n                }\n                _signerFlag = value;\n            }\n        }\n\n        internal const uint CimManifestSignerFlagMask = (uint)0x00000001;\n    }\n\n    internal class CmiStrongNameSignerInfo\n    {\n        private int _error = 0;\n        private string _publicKeyToken = null;\n        private AsymmetricAlgorithm _snKey = null;\n\n        internal CmiStrongNameSignerInfo() { }\n\n        internal CmiStrongNameSignerInfo(int errorCode, string publicKeyToken)\n        {\n            _error = errorCode;\n            _publicKeyToken = publicKeyToken;\n        }\n\n        internal int ErrorCode\n        {\n            get\n            {\n                return _error;\n            }\n\n            set\n            {\n                _error = value;\n            }\n        }\n\n        internal string PublicKeyToken\n        {\n            get\n            {\n                return _publicKeyToken;\n            }\n\n            set\n            {\n                _publicKeyToken = value;\n            }\n        }\n\n        internal AsymmetricAlgorithm PublicKey\n        {\n            get\n            {\n                return _snKey;\n            }\n\n            set\n            {\n                _snKey = value;\n            }\n        }\n    }\n\n    [SupportedOSPlatform(\"windows\")]\n    internal class CmiAuthenticodeSignerInfo\n    {\n        private int _error = 0;\n        private X509Chain _signerChain = null;\n        private uint _algHash = 0;\n        private string _hash = null;\n        private string _description = null;\n        private string _descriptionUrl = null;\n        private CmiAuthenticodeTimestamperInfo _timestamperInfo = null;\n\n        internal CmiAuthenticodeSignerInfo() { }\n\n        internal CmiAuthenticodeSignerInfo(int errorCode)\n        {\n            _error = errorCode;\n        }\n\n        internal CmiAuthenticodeSignerInfo(Win32.AXL_SIGNER_INFO signerInfo,\n                                            Win32.AXL_TIMESTAMPER_INFO timestamperInfo)\n        {\n            _error = (int)signerInfo.dwError;\n            if (signerInfo.pChainContext != IntPtr.Zero)\n            {\n                _signerChain = new X509Chain(signerInfo.pChainContext);\n            }\n\n            _algHash = signerInfo.algHash;\n            if (signerInfo.pwszHash != IntPtr.Zero)\n            {\n                _hash = Marshal.PtrToStringUni(signerInfo.pwszHash);\n            }\n            if (signerInfo.pwszDescription != IntPtr.Zero)\n            {\n                _description = Marshal.PtrToStringUni(signerInfo.pwszDescription);\n            }\n            if (signerInfo.pwszDescriptionUrl != IntPtr.Zero)\n            {\n                _descriptionUrl = Marshal.PtrToStringUni(signerInfo.pwszDescriptionUrl);\n            }\n            if ((int)timestamperInfo.dwError != Win32.TRUST_E_NOSIGNATURE)\n            {\n                _timestamperInfo = new CmiAuthenticodeTimestamperInfo(timestamperInfo);\n            }\n        }\n\n        internal int ErrorCode\n        {\n            get\n            {\n                return _error;\n            }\n            set\n            {\n                _error = value;\n            }\n        }\n\n        internal uint HashAlgId\n        {\n            get\n            {\n                return _algHash;\n            }\n            set\n            {\n                _algHash = value;\n            }\n        }\n\n        internal string Hash\n        {\n            get\n            {\n                return _hash;\n            }\n            set\n            {\n                _hash = value;\n            }\n        }\n\n        internal string Description\n        {\n            get\n            {\n                return _description;\n            }\n            set\n            {\n                _description = value;\n            }\n        }\n\n        internal string DescriptionUrl\n        {\n            get\n            {\n                return _descriptionUrl;\n            }\n            set\n            {\n                _descriptionUrl = value;\n            }\n        }\n\n        internal CmiAuthenticodeTimestamperInfo TimestamperInfo\n        {\n            get\n            {\n                return _timestamperInfo;\n            }\n        }\n\n        internal X509Chain SignerChain\n        {\n            get\n            {\n                return _signerChain;\n            }\n            set\n            {\n                _signerChain = value;\n            }\n        }\n    }\n\n    [SupportedOSPlatform(\"windows\")]\n    internal class CmiAuthenticodeTimestamperInfo\n    {\n        private int _error = 0;\n        private X509Chain _timestamperChain = null;\n        private DateTime _timestampTime;\n        private uint _algHash = 0;\n\n        private CmiAuthenticodeTimestamperInfo() { }\n\n        internal CmiAuthenticodeTimestamperInfo(Win32.AXL_TIMESTAMPER_INFO timestamperInfo)\n        {\n            _error = (int)timestamperInfo.dwError;\n            _algHash = timestamperInfo.algHash;\n            long dt = (((long)(uint)timestamperInfo.ftTimestamp.dwHighDateTime) << 32) | ((long)(uint)timestamperInfo.ftTimestamp.dwLowDateTime);\n            _timestampTime = DateTime.FromFileTime(dt);\n            if (timestamperInfo.pChainContext != IntPtr.Zero)\n            {\n                _timestamperChain = new X509Chain(timestamperInfo.pChainContext);\n            }\n        }\n\n        internal int ErrorCode\n        {\n            get\n            {\n                return _error;\n            }\n        }\n\n        internal uint HashAlgId\n        {\n            get\n            {\n                return _algHash;\n            }\n        }\n\n        internal DateTime TimestampTime\n        {\n            get\n            {\n                return _timestampTime;\n            }\n        }\n\n        internal X509Chain TimestamperChain\n        {\n            get\n            {\n                return _timestamperChain;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.Core {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.Core.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The argument cannot be empty..\n        /// </summary>\n        internal static string ArgumentCannotBeEmpty {\n            get {\n                return ResourceManager.GetString(\"ArgumentCannotBeEmpty\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing SignTool job with {count} files..\n        /// </summary>\n        internal static string AzureSignToolSignatureProviderSigning {\n            get {\n                return ResourceManager.GetString(\"AzureSignToolSignatureProviderSigning\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The certificate is expired..\n        /// </summary>\n        internal static string CertificateIsExpired {\n            get {\n                return ResourceManager.GetString(\"CertificateIsExpired\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The certificate is not yet time valid..\n        /// </summary>\n        internal static string CertificateIsNotYetTimeValid {\n            get {\n                return ResourceManager.GetString(\"CertificateIsNotYetTimeValid\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing Mage job with {count} files..\n        /// </summary>\n        internal static string ClickOnceSignatureProviderSigning {\n            get {\n                return ResourceManager.GetString(\"ClickOnceSignatureProviderSigning\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to {fileName} returned the error {error}.\n        /// </summary>\n        internal static string CliStandardError {\n            get {\n                return ResourceManager.GetString(\"CliStandardError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to {fileName} returned the output {output}.\n        /// </summary>\n        internal static string CliStandardOutput {\n            get {\n                return ResourceManager.GetString(\"CliStandardOutput\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Creating directory {path}..\n        /// </summary>\n        internal static string CreatingDirectory {\n            get {\n                return ResourceManager.GetString(\"CreatingDirectory\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Directory {path} deleted..\n        /// </summary>\n        internal static string DeletedDirectory {\n            get {\n                return ResourceManager.GetString(\"DeletedDirectory\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Deleting directory {path}..\n        /// </summary>\n        internal static string DeletingDirectory {\n            get {\n                return ResourceManager.GetString(\"DeletingDirectory\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Directory {path} still exists..\n        /// </summary>\n        internal static string DirectoryNotDeleted {\n            get {\n                return ResourceManager.GetString(\"DirectoryNotDeleted\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Editing AppInstaller job with {count} files..\n        /// </summary>\n        internal static string EditingAppInstaller {\n            get {\n                return ResourceManager.GetString(\"EditingAppInstaller\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to An unspecified error occurred during VSIX signing..\n        /// </summary>\n        internal static string ErrorSigningVsix {\n            get {\n                return ResourceManager.GetString(\"ErrorSigningVsix\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to An exception occurred while attempting to delete directory {path}..\n        /// </summary>\n        internal static string ExceptionWhileDeletingDirectory {\n            get {\n                return ResourceManager.GetString(\"ExceptionWhileDeletingDirectory\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Multiple private key containers provided. Use either /k for user stores or /km for machine stores..\n        /// </summary>\n        internal static string MultiplePrivateKeyContainersError {\n            get {\n                return ResourceManager.GetString(\"MultiplePrivateKeyContainersError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Private key container missing while using /csp. Use /k or /km to provide a key container..\n        /// </summary>\n        internal static string NoPrivateKeyContainerError {\n            get {\n                return ResourceManager.GetString(\"NoPrivateKeyContainerError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Extracting container {ContainerFilePath} to {DirectoryPath}..\n        /// </summary>\n        internal static string OpeningContainer {\n            get {\n                return ResourceManager.GetString(\"OpeningContainer\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to {0} timed out and could not be killed..\n        /// </summary>\n        internal static string ProcessCouldNotBeKilled {\n            get {\n                return ResourceManager.GetString(\"ProcessCouldNotBeKilled\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to {fileName} took too long to respond. The process exit code is {exitCode}..\n        /// </summary>\n        internal static string ProcessDidNotExitInTime {\n            get {\n                return ResourceManager.GetString(\"ProcessDidNotExitInTime\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to {0} took too long to respond. The process exit code is {1}. Arguments: {2}.\n        /// </summary>\n        internal static string ProcessDidNotExitInTimeWithArguments {\n            get {\n                return ResourceManager.GetString(\"ProcessDidNotExitInTimeWithArguments\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Running {fileName} with parameters: &apos;{args}&apos;..\n        /// </summary>\n        internal static string RunningCli {\n            get {\n                return ResourceManager.GetString(\"RunningCli\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Rebuilding container {ContainerFilePath} from {DirectoryPath}..\n        /// </summary>\n        internal static string SavingContainer {\n            get {\n                return ResourceManager.GetString(\"SavingContainer\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to SignAsync called for {filePath}. Using {localFilePath} locally..\n        /// </summary>\n        internal static string SignAsyncCalled {\n            get {\n                return ResourceManager.GetString(\"SignAsyncCalled\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s..\n        /// </summary>\n        internal static string SigningAttempt {\n            get {\n                return ResourceManager.GetString(\"SigningAttempt\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Could not sign {0}..\n        /// </summary>\n        internal static string SigningFailed {\n            get {\n                return ResourceManager.GetString(\"SigningFailed\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Failed to sign. Attempts exceeded..\n        /// </summary>\n        internal static string SigningFailedAfterAllAttempts {\n            get {\n                return ResourceManager.GetString(\"SigningFailedAfterAllAttempts\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing failed with error {errorCode}..\n        /// </summary>\n        internal static string SigningFailedWithError {\n            get {\n                return ResourceManager.GetString(\"SigningFailedWithError\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing {filePath}..\n        /// </summary>\n        internal static string SigningFile {\n            get {\n                return ResourceManager.GetString(\"SigningFile\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing {filePath} succeeded..\n        /// </summary>\n        internal static string SigningSucceeded {\n            get {\n                return ResourceManager.GetString(\"SigningSucceeded\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Completed in {millseconds} ms..\n        /// </summary>\n        internal static string SigningSucceededWithTimeElapsed {\n            get {\n                return ResourceManager.GetString(\"SigningSucceededWithTimeElapsed\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Submitting {filePath} for signing..\n        /// </summary>\n        internal static string SubmittingFileForSigning {\n            get {\n                return ResourceManager.GetString(\"SubmittingFileForSigning\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Signing VsixSignTool job with {count} files..\n        /// </summary>\n        internal static string VsixSignatureProviderSigning {\n            get {\n                return ResourceManager.GetString(\"VsixSignatureProviderSigning\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Specified {0} is invalid..\n        /// </summary>\n        internal static string VSIXSignToolOpcContentTypeInvalid {\n            get {\n                return ResourceManager.GetString(\"VSIXSignToolOpcContentTypeInvalid\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unknown signing algorithm..\n        /// </summary>\n        internal static string VSIXSignToolUnknownSigningAlgorithm {\n            get {\n                return ResourceManager.GetString(\"VSIXSignToolUnknownSigningAlgorithm\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The algorithm selected is not supported..\n        /// </summary>\n        internal static string VSIXSignToolUnsupportedAlgorithm {\n            get {\n                return ResourceManager.GetString(\"VSIXSignToolUnsupportedAlgorithm\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"ArgumentCannotBeEmpty\" xml:space=\"preserve\">\n    <value>The argument cannot be empty.</value>\n  </data>\n  <data name=\"AzureSignToolSignatureProviderSigning\" xml:space=\"preserve\">\n    <value>Signing SignTool job with {count} files.</value>\n    <comment>{Placeholder=\"{count}\"} is the number of files to be signed.</comment>\n  </data>\n  <data name=\"CertificateIsExpired\" xml:space=\"preserve\">\n    <value>The certificate is expired.</value>\n  </data>\n  <data name=\"CertificateIsNotYetTimeValid\" xml:space=\"preserve\">\n    <value>The certificate is not yet time valid.</value>\n    <comment>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</comment>\n  </data>\n  <data name=\"ClickOnceSignatureProviderSigning\" xml:space=\"preserve\">\n    <value>Signing Mage job with {count} files.</value>\n    <comment>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</comment>\n  </data>\n  <data name=\"CliStandardError\" xml:space=\"preserve\">\n    <value>{fileName} returned the error {error}</value>\n    <comment>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</comment>\n  </data>\n  <data name=\"CliStandardOutput\" xml:space=\"preserve\">\n    <value>{fileName} returned the output {output}</value>\n    <comment>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</comment>\n  </data>\n  <data name=\"CreatingDirectory\" xml:space=\"preserve\">\n    <value>Creating directory {path}.</value>\n    <comment>{Placeholder=\"{path}\"} is a directory path.</comment>\n  </data>\n  <data name=\"DeletedDirectory\" xml:space=\"preserve\">\n    <value>Directory {path} deleted.</value>\n    <comment>{Placeholder=\"{path}\"} is a directory path.</comment>\n  </data>\n  <data name=\"DeletingDirectory\" xml:space=\"preserve\">\n    <value>Deleting directory {path}.</value>\n    <comment>{Placeholder=\"{path}\"} is a directory path.</comment>\n  </data>\n  <data name=\"DirectoryNotDeleted\" xml:space=\"preserve\">\n    <value>Directory {path} still exists.</value>\n    <comment>{Placeholder=\"{path}\"} is a directory path.</comment>\n  </data>\n  <data name=\"EditingAppInstaller\" xml:space=\"preserve\">\n    <value>Editing AppInstaller job with {count} files.</value>\n    <comment>{Placeholder=\"{count}\"} is the number of files to be signed.</comment>\n  </data>\n  <data name=\"ErrorSigningVsix\" xml:space=\"preserve\">\n    <value>An unspecified error occurred during VSIX signing.</value>\n  </data>\n  <data name=\"ExceptionWhileDeletingDirectory\" xml:space=\"preserve\">\n    <value>An exception occurred while attempting to delete directory {path}.</value>\n    <comment>{Placeholder=\"{path}\"} is a directory path.</comment>\n  </data>\n  <data name=\"MultiplePrivateKeyContainersError\" xml:space=\"preserve\">\n    <value>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</value>\n  </data>\n  <data name=\"NoPrivateKeyContainerError\" xml:space=\"preserve\">\n    <value>Private key container missing while using /csp. Use /k or /km to provide a key container.</value>\n  </data>\n  <data name=\"OpeningContainer\" xml:space=\"preserve\">\n    <value>Extracting container {ContainerFilePath} to {DirectoryPath}.</value>\n    <comment>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</comment>\n  </data>\n  <data name=\"ProcessCouldNotBeKilled\" xml:space=\"preserve\">\n    <value>{0} timed out and could not be killed.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is a file path.</comment>\n  </data>\n  <data name=\"ProcessDidNotExitInTime\" xml:space=\"preserve\">\n    <value>{fileName} took too long to respond. The process exit code is {exitCode}.</value>\n    <comment>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</comment>\n  </data>\n  <data name=\"ProcessDidNotExitInTimeWithArguments\" xml:space=\"preserve\">\n    <value>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</comment>\n  </data>\n  <data name=\"RunningCli\" xml:space=\"preserve\">\n    <value>Running {fileName} with parameters: '{args}'.</value>\n    <comment>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</comment>\n  </data>\n  <data name=\"SavingContainer\" xml:space=\"preserve\">\n    <value>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</value>\n    <comment>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</comment>\n  </data>\n  <data name=\"SignAsyncCalled\" xml:space=\"preserve\">\n    <value>SignAsync called for {filePath}. Using {localFilePath} locally.</value>\n    <comment>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</comment>\n  </data>\n  <data name=\"SigningAttempt\" xml:space=\"preserve\">\n    <value>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</value>\n    <comment>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</comment>\n  </data>\n  <data name=\"SigningFailed\" xml:space=\"preserve\">\n    <value>Could not sign {0}.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is a file path.</comment>\n  </data>\n  <data name=\"SigningFailedAfterAllAttempts\" xml:space=\"preserve\">\n    <value>Failed to sign. Attempts exceeded.</value>\n  </data>\n  <data name=\"SigningFailedWithError\" xml:space=\"preserve\">\n    <value>Signing failed with error {errorCode}.</value>\n    <comment>{Placeholder=\"{errorCode}\"} is an error code.</comment>\n  </data>\n  <data name=\"SigningFile\" xml:space=\"preserve\">\n    <value>Signing {filePath}.</value>\n    <comment>{Placeholder=\"{filePath}\"} is a file path.</comment>\n  </data>\n  <data name=\"SigningSucceeded\" xml:space=\"preserve\">\n    <value>Signing {filePath} succeeded.</value>\n    <comment>{Placeholder=\"{filePath}\"} is a file path.</comment>\n  </data>\n  <data name=\"SigningSucceededWithTimeElapsed\" xml:space=\"preserve\">\n    <value>Completed in {millseconds} ms.</value>\n    <comment>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</comment>\n  </data>\n  <data name=\"SubmittingFileForSigning\" xml:space=\"preserve\">\n    <value>Submitting {filePath} for signing.</value>\n    <comment>{Placeholder=\"{filePath}\"} is a file path.</comment>\n  </data>\n  <data name=\"VsixSignatureProviderSigning\" xml:space=\"preserve\">\n    <value>Signing VsixSignTool job with {count} files.</value>\n    <comment>{Placeholder=\"{count}\"} is the number of files to be signed.</comment>\n  </data>\n  <data name=\"VSIXSignToolOpcContentTypeInvalid\" xml:space=\"preserve\">\n    <value>Specified {0} is invalid.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</comment>\n  </data>\n  <data name=\"VSIXSignToolUnknownSigningAlgorithm\" xml:space=\"preserve\">\n    <value>Unknown signing algorithm.</value>\n  </data>\n  <data name=\"VSIXSignToolUnsupportedAlgorithm\" xml:space=\"preserve\">\n    <value>The algorithm selected is not supported.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.Core/ServiceProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Configuration;\n\nnamespace Sign.Core\n{\n    internal sealed class ServiceProvider : IServiceProvider\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        // Dependency injection requires a public constructor.\n        public ServiceProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            _serviceProvider = serviceProvider;\n        }\n\n        public object? GetService(Type serviceType)\n        {\n            return _serviceProvider.GetService(serviceType);\n        }\n\n        internal static ServiceProvider CreateDefault(\n            LogLevel logLevel = LogLevel.Information,\n            ILoggerProvider? loggerProvider = null,\n            Action<IServiceCollection>? addServices = null)\n        {\n            IServiceCollection services = new ServiceCollection();\n            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();\n            AppRootDirectoryLocator locator = new();\n\n            configurationBuilder.SetBasePath(locator.Directory.FullName)\n                .AddJsonFile(\"appsettings.json\", optional: true, reloadOnChange: false)\n                .AddEnvironmentVariables();\n\n            IConfiguration configuration = configurationBuilder.Build();\n            IConfigurationSection loggingSection = configuration.GetSection(\"Logging\");\n\n            services.AddLogging(builder =>\n            {\n                builder = builder.SetMinimumLevel(logLevel)\n                    .AddConfiguration(loggingSection)\n                    .AddConsole();\n\n                if (loggerProvider is not null)\n                {\n                    builder.AddProvider(loggerProvider);\n                }\n            });\n\n            services.AddSingleton<IAppRootDirectoryLocator, AppRootDirectoryLocator>();\n            services.AddSingleton<IToolConfigurationProvider, ToolConfigurationProvider>();\n            services.AddSingleton<IMatcherFactory, MatcherFactory>();\n            services.AddSingleton<IFileListReader, FileListReader>();\n            services.AddSingleton<IFileMatcher, FileMatcher>();\n            services.AddSingleton<IContainerProvider, ContainerProvider>();\n            services.AddSingleton<IFileMetadataService, FileMetadataService>();\n            services.AddSingleton<IDirectoryService, DirectoryService>();\n            services.AddSingleton<IDataFormatSigner, AzureSignToolSigner>();\n            services.AddSingleton<IDataFormatSigner, ClickOnceSigner>();\n            services.AddSingleton<IDataFormatSigner, VsixSigner>();\n            services.AddSingleton<IDataFormatSigner, NuGetSigner>();\n            services.AddSingleton<IDataFormatSigner, AppInstallerServiceSigner>();\n            services.AddSingleton<IDefaultDataFormatSigner, DefaultSigner>();\n            services.AddSingleton<IAggregatingDataFormatSigner, AggregatingSigner>();\n            services.AddSingleton<IManifestSigner, ManifestSigner>();\n            services.AddSingleton<IMageCli, MageCli>();\n            services.AddSingleton<IMakeAppxCli, MakeAppxCli>();\n            services.AddSingleton<INuGetSignTool, NuGetSignTool>();\n            services.AddSingleton<IVsixSignTool, VsixSignTool>();\n            services.AddSingleton<ICertificateVerifier, CertificateVerifier>();\n            services.AddSingleton<ISigner, Signer>();\n\n            if (addServices is not null)\n            {\n                addServices(services);\n            }\n\n            return new ServiceProvider(services.BuildServiceProvider());\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/ServiceProviderFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class ServiceProviderFactory : IServiceProviderFactory\n    {\n        private Action<IServiceCollection>? _addServices;\n\n        public IServiceProvider Create(\n            LogLevel logLevel = LogLevel.Information,\n            ILoggerProvider? loggerProvider = null,\n            Action<IServiceCollection>? addServices = null)\n        {\n\n            if (_addServices is not null)\n            {\n                addServices += _addServices;\n            }\n\n            return ServiceProvider.CreateDefault(logLevel, loggerProvider, addServices);\n        }\n\n        public void AddServices(Action<IServiceCollection> addServices)\n        {\n            ArgumentNullException.ThrowIfNull(addServices, nameof(addServices));\n\n            _addServices += addServices;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Sign.Core.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <IsShipping>true</IsShipping>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AzureSign.Core\" PrivateAssets=\"analyzers;build;compile;contentfiles\" />\n    <PackageReference Include=\"Microsoft.Dynamics.BusinessCentral.Sip.Main\" />\n    <PackageReference Include=\"Microsoft.Extensions.Azure\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.EnvironmentVariables\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Json\" />\n    <PackageReference Include=\"Microsoft.Extensions.FileSystemGlobbing\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Console\" PrivateAssets=\"analyzers;build;compile;contentfiles\" />\n    <PackageReference Include=\"NuGet.Packaging\" />\n    <PackageReference Include=\"NuGet.Protocol\" />\n    <PackageReference Include=\"System.Security.Cryptography.Pkcs\" PrivateAssets=\"analyzers;build;compile;contentfiles\" />\n    <PackageReference Include=\"System.Security.Cryptography.Xml\" PrivateAssets=\"analyzers;build;compile;contentfiles\" />\n    <PackageReference Include=\"System.Text.Json\" PrivateAssets=\"analyzers;build;compile;contentfiles\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"sign\" />\n    <InternalsVisibleTo Include=\"Sign.Cli.Test\" />\n    <InternalsVisibleTo Include=\"Sign.Core.Test\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.CertificateStore\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.CertificateStore.Test\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.KeyVault\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.KeyVault.Test\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.ArtifactSigning\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.ArtifactSigning.Test\" />\n    <InternalsVisibleTo Include=\"Sign.TestInfrastructure\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Sign.Core/Signer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Security.Authentication;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class Signer : ISigner\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly ILogger<ISigner> _logger;\n\n        // Dependency injection requires a public constructor.\n        public Signer(IServiceProvider serviceProvider, ILogger<ISigner> logger)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _serviceProvider = serviceProvider;\n            _logger = logger;\n        }\n\n        public async Task<int> SignAsync(\n            IReadOnlyList<FileInfo> inputFiles,\n            string? outputFile,\n            FileInfo? fileList,\n            bool recurseContainers,\n            DirectoryInfo baseDirectory,\n            string? applicationName,\n            string? publisherName,\n            string? description,\n            Uri? descriptionUrl,\n            Uri timestampUrl,\n            int maxConcurrency,\n            HashAlgorithmName fileHashAlgorithm,\n            HashAlgorithmName timestampHashAlgorithm)\n        {\n            IAggregatingDataFormatSigner signer = _serviceProvider.GetRequiredService<IAggregatingDataFormatSigner>();\n            IDirectoryService directoryService = _serviceProvider.GetRequiredService<IDirectoryService>();\n            ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxConcurrency };\n\n            Matcher? matcher = null;\n            Matcher? antiMatcher = null;\n\n            if (fileList is not null)\n            {\n                IFileListReader fileListReader = _serviceProvider.GetRequiredService<IFileListReader>();\n\n                using (FileStream stream = fileList.OpenRead())\n                using (StreamReader reader = new(stream))\n                {\n                    fileListReader.Read(reader, out matcher, out antiMatcher);\n                }\n            }\n\n            ICertificateProvider certificateProvider = _serviceProvider.GetRequiredService<ICertificateProvider>();\n\n            SignOptions signOptions = new(\n                applicationName,\n                publisherName,\n                description,\n                descriptionUrl,\n                fileHashAlgorithm,\n                timestampHashAlgorithm,\n                timestampUrl,\n                matcher,\n                antiMatcher,\n                recurseContainers);\n\n            try\n            {\n                using (X509Certificate2 certificate = await certificateProvider.GetCertificateAsync())\n                {\n                    ICertificateVerifier certificateVerifier = _serviceProvider.GetRequiredService<ICertificateVerifier>();\n\n                    certificateVerifier.Verify(certificate);\n                }\n\n                await Parallel.ForEachAsync(inputFiles, parallelOptions, async (input, token) =>\n                {\n                    FileInfo output;\n\n                    Stopwatch sw = Stopwatch.StartNew();\n\n                    // Special case if there's only one input file and the output has a value, treat it as a file\n                    if (inputFiles.Count == 1 && !string.IsNullOrWhiteSpace(outputFile))\n                    {\n                        // See if it has a file extension and if not, treat as a directory and use the input file name\n                        if (Path.HasExtension(outputFile))\n                        {\n                            output = new FileInfo(ExpandFilePath(baseDirectory, outputFile));\n                        }\n                        else\n                        {\n                            output = new FileInfo(Path.Combine(ExpandFilePath(baseDirectory, outputFile), inputFiles[0].Name));\n                        }\n                    }\n                    else\n                    {\n                        // if the output is specified, treat it as a directory, if not, overwrite the current file\n                        if (string.IsNullOrWhiteSpace(outputFile))\n                        {\n                            output = new FileInfo(input.FullName);\n                        }\n                        else\n                        {\n                            var relative = Path.GetRelativePath(baseDirectory.FullName, input.FullName);\n\n                            var basePath = Path.IsPathRooted(outputFile) ?\n                                           outputFile :\n                                           $\"{baseDirectory}{Path.DirectorySeparatorChar}{outputFile}\";\n\n                            var fullOutput = Path.Combine(basePath, relative);\n\n                            output = new FileInfo(fullOutput);\n                        }\n                    }\n\n                    //Ensure the output directory exists\n                    Directory.CreateDirectory(output.DirectoryName!);\n\n                    //Do action\n\n                    _logger.LogInformation(Resources.SubmittingFileForSigning, input.FullName);\n\n                    // this might have two files, one containing the file list\n                    // The first will be the package and the second is the filter\n                    using (TemporaryDirectory temporaryDirectory = new(directoryService))\n                    {\n                        string inputFileName = Path.Combine(temporaryDirectory.Directory.FullName, Path.GetRandomFileName());\n                        // However check its extension as it might be important (e.g. zip, bundle, etc)\n                        if (signer.CanSign(input))\n                        {\n                            // Keep the input extenstion as it has significance.\n                            inputFileName = Path.ChangeExtension(inputFileName, input.Extension);\n                        }\n\n                        _logger.LogInformation(Resources.SignAsyncCalled, input.FullName, inputFileName);\n\n                        if (input.Length > 0)\n                        {\n                            input.CopyTo(inputFileName, overwrite: true);\n                            // for things like clickonce we will need additional files from the source location\n                            // in order to fully sign everything, so ask the signature provider to do it for us.\n                            signer.CopySigningDependencies(input, temporaryDirectory.Directory, signOptions);\n                        }\n\n                        FileInfo fi = new(inputFileName);\n\n                        await signer.SignAsync(new[] { fi }, signOptions);\n\n                        // copy everything back\n                        fi.CopyTo(output.FullName, overwrite: true);\n                        signer.CopySigningDependencies(fi, output.Directory!, signOptions);\n                    }\n\n                    _logger.LogInformation(Resources.SigningSucceededWithTimeElapsed, sw.ElapsedMilliseconds);\n                });\n            }\n            catch (AuthenticationException e)\n            {\n                _logger.LogError(e, e.Message);\n                return ExitCode.Failed;\n            }\n            catch (SigningException)\n            {\n                _logger.LogError(Resources.SigningFailedAfterAllAttempts);\n                return ExitCode.Failed;\n            }\n            catch (Exception e)\n            {\n                _logger.LogError(e, e.Message);\n                return ExitCode.Failed;\n            }\n\n            return ExitCode.Success;\n        }\n\n        private static string ExpandFilePath(DirectoryInfo baseDirectory, string file)\n        {\n            if (!Path.IsPathRooted(file))\n            {\n                return Path.Combine(baseDirectory.FullName, file);\n            }\n\n            return file;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/SigningException.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class SigningException : Exception\n    {\n        public SigningException()\n        {\n        }\n\n        public SigningException(string message)\n            : base(message)\n        {\n        }\n\n        public SigningException(string message, Exception inner)\n            : base(message, inner)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/CliTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Globalization;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal abstract class CliTool : Tool, ICliTool\n    {\n        protected FileInfo Cli { get; }\n\n        internal CliTool(\n            FileInfo cli,\n            ILogger<ICliTool> logger)\n            : base(logger)\n        {\n            ArgumentNullException.ThrowIfNull(cli, nameof(cli));\n\n            Cli = cli;\n        }\n\n        public async Task<int> RunAsync(string? args)\n        {\n            using (Process process = new())\n            {\n                process.StartInfo = new ProcessStartInfo()\n                {\n                    FileName = Cli.FullName,\n                    UseShellExecute = false,\n                    CreateNoWindow = true,\n                    RedirectStandardError = true,\n                    RedirectStandardOutput = true,\n                    RedirectStandardInput = true,\n                    Arguments = args\n                };\n\n                Logger.LogInformation(Resources.RunningCli, Cli.Name, args);\n\n                process.Start();\n\n                // Close stdin so the child process cannot block waiting for input.\n                process.StandardInput.Close();\n\n                // Read stdout and stderr concurrently to avoid a deadlock where the child\n                // process blocks writing to a full pipe buffer while this process blocks\n                // waiting for the other stream's ReadToEnd to complete.\n                Task<string> outputTask = process.StandardOutput.ReadToEndAsync();\n                Task<string> errorTask = process.StandardError.ReadToEndAsync();\n\n                await Task.WhenAll(outputTask, errorTask);\n\n                string output = outputTask.Result;\n                string error = errorTask.Result;\n\n                Logger.LogInformation(Resources.CliStandardOutput, Cli.Name, output);\n\n                if (!string.IsNullOrWhiteSpace(error))\n                {\n                    Logger.LogInformation(Resources.CliStandardError, Cli.Name, error);\n                }\n\n                using (CancellationTokenSource cancellationTokenSource = new())\n                {\n                    cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30));\n\n                    try\n                    {\n                        await process.WaitForExitAsync(cancellationTokenSource.Token);\n                    }\n                    catch (OperationCanceledException)\n                    {\n                        // The process has not exited, so process.ExitCode is unavailable.\n                        int exitCode = ExitCode.Failed;\n\n                        Logger.LogError(Resources.ProcessDidNotExitInTime, Cli.Name, exitCode);\n\n                        try\n                        {\n                            process.Kill();\n                        }\n                        catch (Exception ex)\n                        {\n                            string killMessage = string.Format(CultureInfo.CurrentCulture, Resources.ProcessCouldNotBeKilled, Cli.Name);\n\n                            throw new Exception(killMessage, ex);\n                        }\n\n                        string message = string.Format(\n                            CultureInfo.CurrentCulture,\n                            Resources.ProcessDidNotExitInTimeWithArguments,\n                            Cli.Name,\n                            exitCode,\n                            process.StartInfo.Arguments);\n\n                        throw new Exception(message);\n                    }\n\n                    return process.ExitCode;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/ICliTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface ICliTool : ITool\n    {\n        Task<int> RunAsync(string? args);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/IMageCli.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IMageCli : ICliTool\n    {\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/IMakeAppxCli.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IMakeAppxCli : ICliTool\n    {\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/INuGetSignTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    internal interface INuGetSignTool : ITool\n    {\n        Task<bool> SignAsync(FileInfo file, RSA rsaPrivateKey, X509Certificate2 certificate, SignOptions options);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/ITool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface ITool\n    {\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/IToolConfigurationProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IToolConfigurationProvider\n    {\n        FileInfo Mage { get; }\n        FileInfo MakeAppx { get; }\n        FileInfo SignToolManifest { get; }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/IVsixSignTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal interface IVsixSignTool : ITool\n    {\n        Task<bool> SignAsync(FileInfo file, SignConfigurationSet configuration, SignOptions options);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/MageCli.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class MageCli : CliTool, IMageCli\n    {\n        // Dependency injection requires a public constructor.\n        public MageCli(\n            IToolConfigurationProvider toolConfigurationProvider,\n            ILogger<IMageCli> logger)\n            : base(toolConfigurationProvider.Mage, logger)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/MakeAppxCli.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class MakeAppxCli : CliTool, IMakeAppxCli\n    {\n        // Dependency injection requires a public constructor.\n        public MakeAppxCli(\n            IToolConfigurationProvider toolConfigurationProvider,\n            ILogger<IMakeAppxCli> logger)\n            : base(toolConfigurationProvider.MakeAppx, logger)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/NuGet/NuGetLogger.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing NuGet.Common;\nusing LogLevel = NuGet.Common.LogLevel;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetLogger : NuGet.Common.ILogger\n    {\n        private readonly Microsoft.Extensions.Logging.ILogger _logger;\n        private readonly string _fileName;\n\n        internal NuGetLogger(Microsoft.Extensions.Logging.ILogger logger, string fileName)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n            ArgumentException.ThrowIfNullOrEmpty(fileName, nameof(fileName));\n\n            _logger = logger;\n            _fileName = fileName;\n        }\n\n        public void Log(LogLevel level, string data)\n        {\n            _logger.Log(ConvertLevel(level), $\"NuGet [{_fileName}]: {data}\");\n        }\n\n        public void Log(ILogMessage message)\n        {\n            Log(message.Level, message.FormatWithCode());\n        }\n\n        public Task LogAsync(LogLevel level, string data)\n        {\n            Log(level, data);\n\n            return Task.CompletedTask;\n        }\n\n        public Task LogAsync(ILogMessage message)\n        {\n            Log(message.Level, message.FormatWithCode());\n\n            return Task.CompletedTask;\n        }\n\n        public void LogDebug(string data)\n        {\n            Log(LogLevel.Debug, data);\n        }\n\n        public void LogError(string data)\n        {\n            Log(LogLevel.Error, data);\n        }\n\n        public void LogInformation(string data)\n        {\n            Log(LogLevel.Information, data);\n        }\n\n        public void LogInformationSummary(string data)\n        {\n            Log(LogLevel.Information, data);\n        }\n\n        public void LogMinimal(string data)\n        {\n            Log(LogLevel.Minimal, data);\n        }\n\n        public void LogVerbose(string data)\n        {\n            Log(LogLevel.Verbose, data);\n        }\n\n        public void LogWarning(string data)\n        {\n            Log(LogLevel.Warning, data);\n        }\n\n        private static Microsoft.Extensions.Logging.LogLevel ConvertLevel(LogLevel level)\n        {\n            return level switch\n            {\n                LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug,\n                LogLevel.Verbose => Microsoft.Extensions.Logging.LogLevel.Trace,\n                LogLevel.Information => Microsoft.Extensions.Logging.LogLevel.Information,\n                LogLevel.Minimal => Microsoft.Extensions.Logging.LogLevel.Information,\n                LogLevel.Warning => Microsoft.Extensions.Logging.LogLevel.Warning,\n                LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error,\n                _ => Microsoft.Extensions.Logging.LogLevel.Information\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/NuGet/NuGetPackageSigner.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing NuGet.Common;\nusing NuGet.Packaging.Signing;\nusing NuGet.Protocol;\nusing ILogger = Microsoft.Extensions.Logging.ILogger;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetPackageSigner\n    {\n        private readonly ILogger _logger;\n\n        public NuGetPackageSigner(ILogger logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _logger = logger;\n        }\n\n        public async Task<bool> SignAsync(\n            string packagePath,\n            string outputPath,\n            Uri timestampUrl,\n            SignatureType signatureType,\n            HashAlgorithmName signatureHashAlgorithm,\n            HashAlgorithmName timestampHashAlgorithm,\n            X509Certificate2 signingCertificate,\n            System.Security.Cryptography.RSA rsa,\n            bool overwrite,\n            CancellationToken cancellationToken = default)\n        {\n            ArgumentException.ThrowIfNullOrEmpty(packagePath, nameof(packagePath));\n            ArgumentException.ThrowIfNullOrEmpty(outputPath, nameof(outputPath));\n            ArgumentNullException.ThrowIfNull(timestampUrl, nameof(timestampUrl));\n            ArgumentNullException.ThrowIfNull(signingCertificate, nameof(signingCertificate));\n            ArgumentNullException.ThrowIfNull(rsa, nameof(rsa));\n\n            bool inPlaceSigning = String.Equals(packagePath, outputPath);\n            bool usingWildCards = packagePath.Contains('*') || packagePath.Contains('?');\n            IEnumerable<string> packageFilePaths = LocalFolderUtility.ResolvePackageFromPath(packagePath);\n            NuGetSignatureProvider signatureProvider = new(rsa, new Rfc3161TimestampProvider(timestampUrl));\n            SignPackageRequest? request = null;\n\n            if (signatureType == SignatureType.Author)\n            {\n                request = new AuthorSignPackageRequest(signingCertificate, signatureHashAlgorithm, timestampHashAlgorithm);\n            }\n            else\n            {\n                throw new NotSupportedException(nameof(signatureType));\n            }\n\n            foreach (string packageFilePath in packageFilePaths)\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n\n                string packageFileName = Path.GetFileName(packageFilePath);\n\n                _logger.LogInformation($\"{nameof(SignAsync)} [{packageFilePath}]: Begin signing {packageFileName}\");\n\n                string? originalPackageCopyPath = null;\n\n                try\n                {\n                    originalPackageCopyPath = CopyPackage(packageFilePath);\n                    string signedPackagePath = outputPath;\n\n                    if (inPlaceSigning)\n                    {\n                        signedPackagePath = packageFilePath;\n                    }\n                    else if (usingWildCards)\n                    {\n                        string? pathName = Path.GetDirectoryName(outputPath + Path.DirectorySeparatorChar);\n\n                        if (!string.IsNullOrEmpty(pathName) && !Directory.Exists(pathName))\n                        {\n                            Directory.CreateDirectory(pathName);\n                        }\n\n                        signedPackagePath = pathName + Path.DirectorySeparatorChar + packageFileName;\n                    }\n\n                    using (SigningOptions options = SigningOptions.CreateFromFilePaths(\n                        originalPackageCopyPath,\n                        signedPackagePath,\n                        overwrite,\n                        signatureProvider,\n                        new NuGetLogger(_logger, packageFilePath)))\n                    {\n                        await SigningUtility.SignAsync(options, request, cancellationToken);\n                    }\n                }\n                catch (Exception e)\n                {\n                    _logger.LogError(e, e.Message);\n                    return false;\n                }\n                finally\n                {\n                    if (!string.IsNullOrEmpty(originalPackageCopyPath))\n                    {\n                        try\n                        {\n                            FileUtility.Delete(originalPackageCopyPath);\n                        }\n                        catch\n                        {\n                        }\n                    }\n\n                    _logger.LogInformation($\"{nameof(SignAsync)} [{packageFilePath}]: End signing {packageFileName}\");\n                }\n            }\n\n            return true;\n        }\n\n        private static string CopyPackage(string sourceFilePath)\n        {\n            string destFilePath = Path.GetTempFileName();\n\n            File.Copy(sourceFilePath, destFilePath, overwrite: true);\n\n            return destFilePath;\n        }\n\n        private static void OverwritePackage(string sourceFilePath, string destFilePath)\n        {\n            File.Copy(sourceFilePath, destFilePath, overwrite: true);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/NuGet/NuGetSignatureProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Reflection;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing NuGet.Common;\nusing NuGet.Packaging.Signing;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetSignatureProvider : NuGet.Packaging.Signing.ISignatureProvider\n    {\n        // Occurs when SignedCms.ComputeSignature cannot read the certificate private key\n        // \"Invalid provider type specified.\" (INVALID_PROVIDER_TYPE)\n        private const int INVALID_PROVIDER_TYPE_HRESULT = unchecked((int)0x80090014);\n\n        private readonly RSA _rsa;\n        private readonly ITimestampProvider _timestampProvider;\n\n        public NuGetSignatureProvider(RSA rsa, ITimestampProvider timestampProvider)\n        {\n            ArgumentNullException.ThrowIfNull(rsa, nameof(rsa));\n            ArgumentNullException.ThrowIfNull(timestampProvider, nameof(timestampProvider));\n\n            _rsa = rsa;\n            _timestampProvider = timestampProvider;\n        }\n\n        public Task<PrimarySignature> CreatePrimarySignatureAsync(\n            SignPackageRequest request,\n            SignatureContent signatureContent,\n            ILogger logger,\n            CancellationToken token)\n        {\n            if (request is AuthorSignPackageRequest authorSignPackageRequest)\n            {\n                return CreateAuthorSignatureAsync(authorSignPackageRequest, signatureContent, logger, token);\n            }\n\n            throw new NotSupportedException($\"Unsupported {nameof(SignPackageRequest)} type: {request.GetType().Name}\");\n        }\n\n        public Task<PrimarySignature> CreateRepositoryCountersignatureAsync(\n            RepositorySignPackageRequest request,\n            PrimarySignature primarySignature,\n            ILogger logger,\n            CancellationToken token)\n        {\n            throw new NotSupportedException($\"Unsupported {nameof(SignPackageRequest)} type: {request.GetType().Name}\");\n        }\n\n        private async Task<PrimarySignature> CreateAuthorSignatureAsync(\n            AuthorSignPackageRequest request,\n            SignatureContent signatureContent,\n            ILogger logger,\n            CancellationToken token)\n        {\n            ArgumentNullException.ThrowIfNull(request, nameof(request));\n            ArgumentNullException.ThrowIfNull(signatureContent, nameof(signatureContent));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Creating primary signature\");\n            PrimarySignature authorSignature = CreatePrimarySignature(request, signatureContent, logger);\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Primary signature completed\");\n\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Timestamping primary signature\");\n            PrimarySignature timestampedAuthorSignature = await TimestampPrimarySignatureAsync(request, logger, authorSignature, token);\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Timestamping completed\");\n\n            return timestampedAuthorSignature;\n        }\n\n        private PrimarySignature CreatePrimarySignature(AuthorSignPackageRequest request, SignatureContent signatureContent, ILogger logger)\n        {\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Retrieving certificate chain\");\n            const string PropertyName = \"Chain\";\n\n            PropertyInfo? property = typeof(SignPackageRequest)\n                .GetProperty(PropertyName, BindingFlags.Instance | BindingFlags.NonPublic);\n\n            if (property is null)\n            {\n                throw new MissingMemberException(nameof(SignPackageRequest), PropertyName);\n            }\n\n            MethodInfo? getter = property.GetGetMethod(nonPublic: true);\n\n            if (getter is null)\n            {\n                throw new MissingMemberException(nameof(SignPackageRequest), PropertyName);\n            }\n\n            var certificates = (IReadOnlyList<X509Certificate2>?)getter.Invoke(request, parameters: null);\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Retrieved certificate chain\");\n\n\n            logger.LogInformation($\"{nameof(CreateAuthorSignatureAsync)}: Computing signature\");\n            CmsSigner cmsSigner = CreateCmsSigner(request, certificates!);\n            ContentInfo contentInfo = new(signatureContent.GetBytes());\n            SignedCms signedCms = new(contentInfo);\n\n            try\n            {\n                signedCms.ComputeSignature(cmsSigner, silent: false); // silent is false to ensure PIN prompts appear if CNG/CAPI requires it\n            }\n            catch (CryptographicException ex) when (ex.HResult == INVALID_PROVIDER_TYPE_HRESULT)\n            {\n                StringBuilder stringBuilder = new();\n                stringBuilder.AppendLine(\"Invalid _rsa type\");\n                stringBuilder.AppendLine(CertificateUtility.X509Certificate2ToString(request.Certificate, NuGet.Common.HashAlgorithmName.SHA256));\n\n                logger.LogError($\"{nameof(CreateAuthorSignatureAsync)}: Cannot read private key\");\n\n                throw new SignatureException(NuGetLogCode.NU3001, stringBuilder.ToString());\n            }\n\n            return PrimarySignature.Load(signedCms);\n        }\n\n        private CmsSigner CreateCmsSigner(SignPackageRequest request, IReadOnlyList<X509Certificate2> chain)\n        {\n            // Subject Key Identifier (SKI) is smaller and less prone to accidental matching than issuer and serial\n            // number.  However, to ensure cross-platform verification, SKI should only be used if the certificate\n            // has the SKI extension attribute.\n            CmsSigner signer;\n\n            if (request.Certificate.Extensions[Oids.SubjectKeyIdentifier] == null)\n            {\n                signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, request.Certificate, _rsa);\n            }\n            else\n            {\n                signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, request.Certificate, _rsa);\n            }\n\n            foreach (X509Certificate2 certificate in chain)\n            {\n                signer.Certificates.Add(certificate);\n            }\n\n            CryptographicAttributeObjectCollection attributes;\n\n            if (request.SignatureType == SignatureType.Repository)\n            {\n                attributes = SigningUtility.CreateSignedAttributes((RepositorySignPackageRequest)request, chain);\n            }\n            else\n            {\n                attributes = SigningUtility.CreateSignedAttributes(request, chain);\n            }\n\n            foreach (CryptographicAttributeObject attribute in attributes)\n            {\n                signer.SignedAttributes.Add(attribute);\n            }\n\n            // We built the chain ourselves and added certificates.\n            // Passing any other value here would trigger another chain build\n            // and possibly add duplicate certs to the collection.\n            signer.IncludeOption = X509IncludeOption.None;\n            signer.DigestAlgorithm = request.SignatureHashAlgorithm.ConvertToOid();\n\n            return signer;\n        }\n\n        private Task<PrimarySignature> TimestampPrimarySignatureAsync(\n            SignPackageRequest request,\n            ILogger logger,\n            PrimarySignature signature,\n            CancellationToken token)\n        {\n            byte[] signatureValue = signature.GetSignatureValue();\n            byte[] messageHash = request.TimestampHashAlgorithm.ComputeHash(signatureValue);\n\n            TimestampRequest timestampRequest = new(\n                signingSpecifications: SigningSpecifications.V1,\n                hashedMessage: messageHash,\n                hashAlgorithm: request.TimestampHashAlgorithm,\n                target: SignaturePlacement.PrimarySignature);\n\n            return _timestampProvider.TimestampSignatureAsync(signature, timestampRequest, logger, token);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/NuGetSignTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal sealed class NuGetSignTool : Tool, INuGetSignTool\n    {\n        // Dependency injection requires a public constructor.\n        public NuGetSignTool(ILogger<INuGetSignTool> logger)\n            : base(logger)\n        {\n        }\n\n        public async Task<bool> SignAsync(FileInfo packageFile, RSA rsa, X509Certificate2 certificate, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(packageFile, nameof(packageFile));\n            ArgumentNullException.ThrowIfNull(rsa, nameof(rsa));\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            Logger.LogInformation(Resources.SigningFile, packageFile.FullName);\n\n            NuGetPackageSigner signer = new(Logger);\n\n            var result = false;\n\n            try\n            {\n                NuGet.Common.HashAlgorithmName fileHashAlgorithm = FromCryptographyName(options.FileHashAlgorithm);\n                NuGet.Common.HashAlgorithmName timestampHashAlgorithm = FromCryptographyName(options.TimestampHashAlgorithm);\n\n                result = await signer.SignAsync(\n                    packageFile.FullName,\n                    packageFile.FullName,\n                    options.TimestampService,\n                    NuGet.Packaging.Signing.SignatureType.Author,\n                    fileHashAlgorithm,\n                    timestampHashAlgorithm,\n                    certificate,\n                    rsa,\n                    overwrite: true);\n            }\n            catch (Exception e)\n            {\n                Logger.LogError(e, e.Message);\n            }\n\n            return result;\n        }\n\n        private static NuGet.Common.HashAlgorithmName FromCryptographyName(HashAlgorithmName hashAlgorithmName)\n        {\n            if (hashAlgorithmName == HashAlgorithmName.SHA256)\n            {\n                return NuGet.Common.HashAlgorithmName.SHA256;\n            }\n\n            if (hashAlgorithmName == HashAlgorithmName.SHA384)\n            {\n                return NuGet.Common.HashAlgorithmName.SHA384;\n            }\n\n            if (hashAlgorithmName == HashAlgorithmName.SHA512)\n            {\n                return NuGet.Common.HashAlgorithmName.SHA512;\n            }\n\n            throw new ArgumentException(nameof(hashAlgorithmName));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/Tool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core\n{\n    internal abstract class Tool\n    {\n        protected ILogger<ITool> Logger { get; }\n\n        internal Tool(ILogger<ITool> logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            Logger = logger;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/ToolConfigurationProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal sealed class ToolConfigurationProvider : IToolConfigurationProvider\n    {\n        private readonly DirectoryInfo _rootDirectory;\n\n        public FileInfo Mage { get; }\n        public FileInfo MakeAppx { get; }\n        public FileInfo SignToolManifest { get; }\n\n        // Dependency injection requires a public constructor.\n        public ToolConfigurationProvider(IAppRootDirectoryLocator appRootDirectoryLocator)\n        {\n            ArgumentNullException.ThrowIfNull(appRootDirectoryLocator, nameof(appRootDirectoryLocator));\n\n            _rootDirectory = appRootDirectoryLocator.Directory;\n\n            DirectoryInfo sdkDirectory = new(Path.Combine(_rootDirectory.FullName, \"tools\", \"SDK\"));\n\n            Mage = new FileInfo(Path.Combine(sdkDirectory.FullName, \"x86\", \"mage.exe\"));\n            MakeAppx = new FileInfo(Path.Combine(sdkDirectory.FullName, \"x64\", \"makeappx.exe\"));\n            SignToolManifest = new FileInfo(Path.Combine(sdkDirectory.FullName, \"x64\", \"SignTool.exe.manifest\"));\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/HashAlgorithmInfo.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    internal sealed class HashAlgorithmInfo\n    {\n        public HashAlgorithmName Name { get; }\n\n        public Uri XmlDSigIdentifier { get; }\n\n        public Oid Oid { get; }\n\n        private Func<HashAlgorithm> Factory { get; }\n\n        public HashAlgorithm Create() => Factory();\n\n        public HashAlgorithmInfo(HashAlgorithmName name)\n        {\n            Name = name;\n\n            if (name == HashAlgorithmName.SHA256)\n            {\n                XmlDSigIdentifier = OpcKnownUris.HashAlgorithms.Sha256DigestUri;\n                Factory = SHA256.Create;\n                Oid = new Oid(KnownOids.HashAlgorithms.Sha256);\n            }\n            else if (name == HashAlgorithmName.SHA384)\n            {\n                XmlDSigIdentifier = OpcKnownUris.HashAlgorithms.Sha384DigestUri;\n                Factory = SHA384.Create;\n                Oid = new Oid(KnownOids.HashAlgorithms.Sha384);\n            }\n            else if (name == HashAlgorithmName.SHA512)\n            {\n                XmlDSigIdentifier = OpcKnownUris.HashAlgorithms.Sha512DigestUri;\n                Factory = SHA512.Create;\n                Oid = new Oid(KnownOids.HashAlgorithms.Sha512);\n            }\n            else\n            {\n                throw new NotSupportedException(Resources.VSIXSignToolUnsupportedAlgorithm);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/HexHelpers.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class HexHelpers\n    {\n        private static ReadOnlySpan<byte> LookupTable => new byte[]\n        {\n            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',\n            (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',\n            (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E',\n            (byte)'F',\n        };\n\n        internal static bool IsHex(ReadOnlySpan<char> text)\n        {\n            if (text.IsEmpty)\n            {\n                return false;\n            }\n\n            for (var i = 0; i < text.Length; ++i)\n            {\n                char c = text[i];\n\n                if (!char.IsDigit(c) && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        public static bool TryHexEncode(ReadOnlySpan<byte> data, Span<char> buffer)\n        {\n            var charsRequired = data.Length * 2;\n            if (buffer.Length < charsRequired)\n            {\n                return false;\n            }\n            for (int i = 0, j = 0; i < data.Length; i++, j += 2)\n            {\n                var value = data[i];\n                buffer[j] = (char)LookupTable[(value & 0xF0) >> 4];\n                buffer[j + 1] = (char)LookupTable[value & 0x0F];\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/ISignatureBuilderPreset.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Defines an interface for package signing presets.\n    /// </summary>\n    internal interface ISignatureBuilderPreset\n    {\n        /// <summary>\n        /// Returns a collection of parts that should be enqueued for signing.\n        /// </summary>\n        /// <param name=\"package\">A package to list the parts from.</param>\n        /// <returns>A collection of parts.</returns>\n        IEnumerable<OpcPart> GetPartsForSigning(OpcPackage package);\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/ISigningContext.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// An interface for a signing context. Implementors of this interface will be able to\n    /// sign a VSIX package.\n    /// </summary>\n    internal interface ISigningContext\n    {\n        /// <summary>\n        /// Gets the date and time that the context was created.\n        /// Implementers \n        /// </summary>\n        DateTimeOffset ContextCreationTime { get; }\n\n        /// <summary>\n        /// Gets the digest algorithm that is used to compute the digest to sign.\n        /// </summary>\n        HashAlgorithmName FileDigestAlgorithmName { get; }\n\n        /// <summary>\n        /// Gets the public certificate that the public private key pair belong to.\n        /// </summary>\n        X509Certificate2 Certificate { get; }\n\n        /// <summary>\n        /// Gets the signing algorithm used to compute signatures and perform validations.\n        /// </summary>\n        SigningAlgorithm SignatureAlgorithm { get; }\n\n        /// <summary>\n        /// Gets the XmlDSig signature identifier used to perform the signature opertation.\n        /// </summary>\n        Uri XmlDSigIdentifier { get; }\n\n        /// <summary>\n        /// Signs a digest.\n        /// </summary>\n        /// <param name=\"digest\">The digest to sign. This must be digested with the same algorithm as identified in the <see cref=\"FileDigestAlgorithmName\"/>.</param>\n        /// <returns>The signed digest.</returns>\n        byte[] SignDigest(byte[] digest);\n\n        /// <summary>\n        /// Verifies a digest.\n        /// </summary>\n        /// <param name=\"digest\">The digest to verify. This must be digested with the same algorithm as identified in the <see cref=\"FileDigestAlgorithmName\"/>.</param>\n        /// <param name=\"signature\">The signature of the digest to perform validation with.</param>\n        /// <returns>True if the digest is valid, otherwise false.</returns>\n        bool VerifyDigest(byte[] digest, byte[] signature);\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Interop/Crypt32.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Runtime.InteropServices;\n\nnamespace Sign.Core.Interop\n{\n    internal static class Crypt32\n    {\n        [method: DllImport(\"crypt32.dll\", CallingConvention = CallingConvention.Winapi)]\n        public static extern void CryptMemFree(\n            [param: In, MarshalAs(UnmanagedType.SysInt)] IntPtr pv\n        );\n\n        [method: DllImport(\"crypt32.dll\", CallingConvention = CallingConvention.Winapi, SetLastError = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        public static extern bool CryptRetrieveTimeStamp(\n            [param: In, MarshalAs(UnmanagedType.LPWStr)] string wszUrl,\n            [param: In, MarshalAs(UnmanagedType.U4)] CryptRetrieveTimeStampRetrievalFlags dwRetrievalFlags,\n            [param: In, MarshalAs(UnmanagedType.U4)] uint dwTimeout,\n            [param: In, MarshalAs(UnmanagedType.LPStr)] string? pszHashId,\n            [param: In] ref CRYPT_TIMESTAMP_PARA pPara,\n            [param: In, MarshalAs(UnmanagedType.LPArray)] byte[] pbData,\n            [param: In, MarshalAs(UnmanagedType.U4)] uint cbData,\n            [param: Out] out CryptMemorySafeHandle ppTsContext,\n            [param: In, MarshalAs(UnmanagedType.SysInt)] IntPtr ppTsSigner,\n            [param: In, MarshalAs(UnmanagedType.SysInt)] IntPtr phStore\n        );\n    }\n\n    internal enum CryptRetrieveTimeStampRetrievalFlags : uint\n    {\n        NONE = 0x0,\n        TIMESTAMP_DONT_HASH_DATA = 0x01,\n        TIMESTAMP_VERIFY_CONTEXT_SIGNATURE = 0x00000020,\n        TIMESTAMP_NO_AUTH_RETRIEVAL = 0x00020000\n    }\n\n    [type: StructLayout(LayoutKind.Sequential)]\n    internal struct CRYPT_TIMESTAMP_PARA\n    {\n        public string? pszTSAPolicyId;\n        public bool fRequestCerts;\n        public CRYPTOAPI_BLOB Nonce;\n        public uint cExtension;\n        public IntPtr rgExtension;\n    }\n\n    [type: StructLayout(LayoutKind.Sequential)]\n    internal struct CRYPTOAPI_BLOB\n    {\n        public uint cbData;\n        public IntPtr pbData;\n    }\n\n    [type: StructLayout(LayoutKind.Sequential)]\n    internal struct CRYPT_TIMESTAMP_CONTEXT\n    {\n        public uint cbEncoded;\n        public IntPtr pbEncoded;\n        public IntPtr pTimeStamp;\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Interop/CryptMemorySafeHandle.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Interop\n{\n    internal sealed class CryptMemorySafeHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid\n    {\n        public CryptMemorySafeHandle(bool ownsHandle) : base(ownsHandle)\n        {\n        }\n\n        public CryptMemorySafeHandle() : this(true)\n        {\n        }\n\n        protected override bool ReleaseHandle()\n        {\n            Crypt32.CryptMemFree(handle);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/KnownOids.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class KnownOids\n    {\n        public static class HashAlgorithms\n        {\n            public const string Sha256 = \"2.16.840.1.101.3.4.2.1\";\n            public const string Sha384 = \"2.16.840.1.101.3.4.2.2\";\n            public const string Sha512 = \"2.16.840.1.101.3.4.2.3\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcContentTypes.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Xml.Linq;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Represents the mode of a content type.\n    /// </summary>\n    internal enum OpcContentTypeMode\n    {\n        /// <summary>\n        /// This is a default content type.\n        /// </summary>\n        Default,\n\n        /// <summary>\n        /// This is an overriding content type.\n        /// </summary>\n        Override\n    }\n\n    /// <summary>\n    /// Represents a content type defined in a package.\n    /// </summary>\n    [DebuggerDisplay(\"Extension = {Extension}; PartName = {PartName}; ContentType = {ContentType};\")]\n    internal class OpcContentType\n    {\n        /// <summary>\n        /// The extension, without a leading period, of the content type.\n        /// </summary>\n        public string? Extension { get; }\n\n        /// <summary>\n        /// The MIME type of the content.\n        /// </summary>\n        public string ContentType { get; }\n\n        /// <summary>\n        /// The part name of the content.\n        /// </summary>\n        public string? PartName { get; }\n\n        /// <summary>\n        /// The mode of the content type. This can override a previously defined content type.\n        /// </summary>\n        public OpcContentTypeMode Mode { get; }\n\n        /// <summary>\n        /// Creates a new instance of a content type.\n        /// </summary>\n        /// <param name=\"extension\">The extension, without a leading peroid, of the content type.</param>\n        /// <param name=\"contentType\">The MIME type of the content.</param>\n        /// <param name=\"mode\">The mode within the content type.</param>\n        public OpcContentType(string extension, string contentType, OpcContentTypeMode mode)\n            : this(extension, contentType, null, mode)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new instance of a content type.\n        /// </summary>\n        /// <param name=\"extension\">The extension, without a leading period, of the content type.</param>\n        /// <param name=\"contentType\">The MIME type of the content.</param>\n        /// <param name=\"partName\">The part name of the content.</param>\n        /// <param name=\"mode\">The mode within the content type.</param>\n        public OpcContentType(string? extension, string contentType, string? partName, OpcContentTypeMode mode)\n        {\n            Extension = extension;\n            ContentType = contentType;\n            PartName = partName;\n            Mode = mode;\n        }\n    }\n\n    /// <summary>\n    /// Represents a collection of content types in a package.\n    /// </summary>\n    internal class OpcContentTypes : IList<OpcContentType>\n    {\n        private static readonly XNamespace _opcContentTypeNamespace = \"http://schemas.openxmlformats.org/package/2006/content-types\";\n        private readonly List<OpcContentType> _contentTypes = new List<OpcContentType>();\n\n        internal OpcContentTypes(XDocument document, bool isReadOnly)\n        {\n            if (document == null)\n            {\n                throw new ArgumentNullException(nameof(document));\n            }\n\n            IsReadOnly = isReadOnly;\n            var defaults = document.Root?.Elements(_opcContentTypeNamespace + \"Default\");\n            var overrides = document.Root?.Elements(_opcContentTypeNamespace + \"Override\");\n\n            if (defaults != null)\n            {\n                foreach (var @default in defaults)\n                {\n                    ProcessElement(OpcContentTypeMode.Default, @default);\n                }\n            }\n\n            if (overrides != null)\n            {\n                foreach (var @override in overrides)\n                {\n                    ProcessElement(OpcContentTypeMode.Override, @override);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Creates an XML representation of the content types to be placed in the package.\n        /// </summary>\n        /// <returns>An XML document representing the content types.</returns>\n        public XDocument ToXml()\n        {\n            XName TranslateToElementName(OpcContentTypeMode mode)\n            {\n                switch (mode)\n                {\n                    case OpcContentTypeMode.Default:\n                        return _opcContentTypeNamespace + \"Default\";\n                    case OpcContentTypeMode.Override:\n                        return _opcContentTypeNamespace + \"Override\";\n                    default:\n                        throw new ArgumentException(string.Format(Resources.VSIXSignToolOpcContentTypeInvalid, nameof(OpcContentTypeMode)), nameof(mode));\n                }\n            }\n\n            var document = new XDocument();\n            var root = new XElement(_opcContentTypeNamespace + \"Types\");\n\n            foreach (OpcContentType contentType in _contentTypes)\n            {\n                var element = new XElement(TranslateToElementName(contentType.Mode));\n                element.SetAttributeValue(\"Extension\", contentType.Extension);\n                element.SetAttributeValue(\"PartName\", contentType.PartName);\n                element.SetAttributeValue(\"ContentType\", contentType.ContentType);\n                root.Add(element);\n            }\n\n            document.Add(root);\n\n            return document;\n        }\n\n        internal OpcContentTypes(bool isReadOnly)\n        {\n            IsReadOnly = isReadOnly;\n        }\n\n        private void ProcessElement(OpcContentTypeMode mode, XElement element)\n        {\n            var extension = element.Attribute(\"Extension\")?.Value;\n            var partName = element.Attribute(\"PartName\")?.Value;\n            var contentType = element.Attribute(\"ContentType\")?.Value;\n\n            if (contentType != null)\n            {\n                _contentTypes.Add(new OpcContentType(extension, contentType, partName, mode));\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets a content type item by index.\n        /// </summary>\n        /// <param name=\"index\">The index in the collection.</param>\n        /// <returns>A content type instance.</returns>\n        public OpcContentType this[int index]\n        {\n            get => _contentTypes[index];\n            set\n            {\n                AssertNotReadOnly();\n                IsDirty = true;\n                _contentTypes[index] = value;\n            }\n        }\n\n\n        /// <summary>\n        /// Gets the number of content types.\n        /// </summary>\n        public int Count => _contentTypes.Count;\n\n        /// <summary>\n        /// True if the content type collection is read only. This will be true if the package was opened in a read\n        /// only mode. Attempting to modify the content types will result in an exception.\n        /// </summary>\n        public bool IsReadOnly { get; }\n\n        /// <summary>\n        /// Adds a content type to the collection.\n        /// </summary>\n        /// <param name=\"item\">The content type instance to add.</param>\n        public void Add(OpcContentType item)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _contentTypes.Add(item);\n        }\n\n        /// <summary>\n        /// Removes all content types.\n        /// </summary>\n        public void Clear()\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _contentTypes.Clear();\n        }\n\n\n        /// <inheritdoc />\n        public bool Contains(OpcContentType item) => _contentTypes.Contains(item);\n\n        /// <inheritdoc />\n        public void CopyTo(OpcContentType[] array, int arrayIndex) => _contentTypes.CopyTo(array, arrayIndex);\n\n        /// <inheritdoc />\n        public IEnumerator<OpcContentType> GetEnumerator() => _contentTypes.GetEnumerator();\n\n        /// <inheritdoc />\n        public int IndexOf(OpcContentType item) => _contentTypes.IndexOf(item);\n\n        /// <inheritdoc />\n        public void Insert(int index, OpcContentType item)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _contentTypes.Insert(index, item);\n        }\n\n        /// <inheritdoc />\n        public bool Remove(OpcContentType item)\n        {\n            AssertNotReadOnly();\n            return IsDirty = _contentTypes.Remove(item);\n        }\n\n        /// <inheritdoc />\n        public void RemoveAt(int index)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _contentTypes.RemoveAt(index);\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        internal bool IsDirty { get; set; }\n\n        private void AssertNotReadOnly()\n        {\n            if (IsReadOnly)\n            {\n                throw new InvalidOperationException(\"Cannot update content types in a read only package. Please open the package in write mode.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcKnownMimeTypes.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class OpcKnownMimeTypes\n    {\n        public const string DigitalSignatureOrigin = \"application/vnd.openxmlformats-package.digital-signature-origin\";\n        public const string DigitalSignatureSignature = \"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml\";\n        public const string OpenXmlRelationship = \"application/vnd.openxmlformats-package.relationships+xml\";\n        public const string OctetString = \"application/octet-stream\";\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcKnownUris.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal static class OpcKnownUris\n    {\n        public static readonly Uri DigitalSignatureOrigin = new Uri(\"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin\", UriKind.Absolute);\n        public static readonly Uri DigitalSignatureSignature = new Uri(\"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature\", UriKind.Absolute);\n\n        public static readonly Uri XmlDSig = new Uri(\"http://www.w3.org/2000/09/xmldsig#\", UriKind.Absolute);\n        public static readonly Uri XmlDigitalSignature = new Uri(\"http://schemas.openxmlformats.org/package/2006/digital-signature\", UriKind.Absolute);\n        public static readonly Uri XmlDSigObject = new Uri(\"http://www.w3.org/2000/09/xmldsig#Object\", UriKind.Absolute);\n\n        public static class SignatureAlgorithms\n        {\n            public static readonly Uri RsaSHA256 = new Uri(\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\", UriKind.Absolute);\n            public static readonly Uri RsaSHA384 = new Uri(\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384\", UriKind.Absolute);\n            public static readonly Uri RsaSHA512 = new Uri(\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512\", UriKind.Absolute);\n        }\n\n        public static class HashAlgorithms\n        {\n            //These are documented here. https://www.iana.org/assignments/xml-security-uris/xml-security-uris.xhtml\n            public static readonly Uri Sha256DigestUri = new Uri(\"http://www.w3.org/2001/04/xmlenc#sha256\", UriKind.Absolute);\n            public static readonly Uri Sha384DigestUri = new Uri(\"http://www.w3.org/2001/04/xmldsig-more#sha384\", UriKind.Absolute);\n            public static readonly Uri Sha512DigestUri = new Uri(\"http://www.w3.org/2001/04/xmlenc#sha512\", UriKind.Absolute);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPackage.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing System.Xml.Linq;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Allow manipulating and signing an OPC package, such as a VSIX.\n    /// </summary>\n    internal class OpcPackage : IDisposable\n    {\n        internal static readonly Uri BasePackageUri = new Uri(\"package:///\", UriKind.Absolute);\n        private const string CONTENT_TYPES_XML = \"[Content_Types].xml\";\n        private const string GLOBAL_RELATIONSHIPS = \"_rels/.rels\";\n\n\n        internal readonly ZipArchive Archive;\n        private readonly OpcPackageFileMode _mode;\n        private bool _disposed;\n        private OpcContentTypes? _contentTypes;\n        private OpcRelationships? _relationships;\n        private readonly Dictionary<string, OpcPart> _partTracker;\n\n        /// <summary>\n        /// Opens an OPC package.\n        /// </summary>\n        /// <param name=\"path\">The path to the OPC package.</param>\n        /// <param name=\"mode\">The mode of the OPC package. Read-only by default.</param>\n        /// <returns>An instance of an <see cref=\"OpcPackage\"/>.</returns>\n        public static OpcPackage Open(string path, OpcPackageFileMode mode = OpcPackageFileMode.Read)\n        {\n            var zipMode = GetZipModeFromOpcPackageMode(mode);\n            var zip = ZipFile.Open(path, zipMode);\n\n            return new OpcPackage(zip, mode);\n        }\n\n        private OpcPackage(ZipArchive archive, OpcPackageFileMode mode)\n        {\n            _disposed = false;\n            Archive = archive;\n            _mode = mode;\n            _partTracker = new Dictionary<string, OpcPart>();\n        }\n\n        /// <summary>\n        /// A collection of content types that are known and registered within the package.\n        /// </summary>\n        public OpcContentTypes ContentTypes\n        {\n            get\n            {\n                if (_contentTypes == null)\n                {\n                    _contentTypes = ConstructContentTypes();\n                }\n                return _contentTypes;\n            }\n        }\n\n        /// <summary>\n        /// Closes the OPC package, and finishes all pending write operations.\n        /// </summary>\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _disposed = true;\n                Flush();\n                Archive.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Gets all package-wide parts.\n        /// </summary>\n        /// <returns>An enumerable source of parts.</returns>\n        public IEnumerable<OpcPart> GetParts()\n        {\n            foreach (var entry in Archive.Entries)\n            {\n                if (entry.FullName.Equals(CONTENT_TYPES_XML, StringComparison.OrdinalIgnoreCase))\n                {\n                    continue;\n                }\n\n                if (!_partTracker.TryGetValue(entry.FullName, out OpcPart? part))\n                {\n                    part = new OpcPart(this, entry.FullName, entry, _mode);\n                    _partTracker.Add(entry.FullName, part);\n                }\n\n                yield return part;\n            }\n        }\n\n        /// <summary>\n        /// Gets a part by URI.\n        /// </summary>\n        /// <param name=\"partUri\">A relative URI to the part.</param>\n        /// <returns>An instance of <see cref=\"OpcPart\"/>, or null if the part cannot be found.</returns>\n        public OpcPart? GetPart(Uri? partUri)\n        {\n            var path = partUri?.ToPackagePath();\n\n            if (!_partTracker.TryGetValue(path ?? string.Empty, out OpcPart? part))\n            {\n                var entry = Archive.GetEntry(path ?? string.Empty);\n\n                if (entry == null)\n                {\n                    return null;\n                }\n\n                part = new OpcPart(this, entry.FullName, entry, _mode);\n                _partTracker.Add(path ?? string.Empty, part);\n            }\n\n            return part;\n        }\n\n        /// <summary>\n        /// Creates a new part.\n        /// </summary>\n        /// <param name=\"partUri\">A relative URI where the part will exist in the package.</param>\n        /// <param name=\"mimeType\">The Content Type of the part. If the content type is not registered in the <see cref=\"ContentTypes\"/>, it will automatically be added.</param>\n        /// <returns>An instance of the part just created.</returns>\n        public OpcPart CreatePart(Uri partUri, string mimeType)\n        {\n            var path = partUri.ToPackagePath();\n\n            if (Archive.GetEntry(path) != null)\n            {\n                throw new InvalidOperationException(\"The part already exists.\");\n            }\n\n            var extension = Path.GetExtension(path).TrimStart('.');\n            if (!ContentTypes.Any(ct => string.Equals(extension, ct.Extension, StringComparison.OrdinalIgnoreCase)))\n            {\n                ContentTypes.Add(new OpcContentType(extension, mimeType.ToLower(), OpcContentTypeMode.Default));\n            }\n\n            var zipEntry = Archive.CreateEntry(path, CompressionLevel.NoCompression);\n            var part = new OpcPart(this, zipEntry.FullName, zipEntry, _mode);\n            _partTracker.Add(zipEntry.FullName, part);\n\n            return part;\n        }\n\n        /// <summary>\n        /// Checks if a part already exists in the package.\n        /// </summary>\n        /// <param name=\"partUri\">A relative URI of the part.</param>\n        /// <returns>True if the part exists, false otherwise.</returns>\n        public bool HasPart(Uri partUri)\n        {\n            var path = partUri.ToPackagePath();\n\n            return Archive.GetEntry(path) != null;\n        }\n\n        /// <summary>\n        /// Removes an existing part from the package, and its relationships.\n        /// </summary>\n        /// <param name=\"part\">The part to remove from the package. Use <see cref=\"GetPart(Uri)\"/> to obtain the part to remove.</param>\n        /// <remarks>This does not validate or clean up other references to this part.</remarks>\n        public void RemovePart(OpcPart part)\n        {\n            var relationshipUri = part.Relationships.DocumentUri;\n            var relationshipPath = relationshipUri.ToPackagePath();\n            var relationshipEntry = Archive.GetEntry(relationshipPath);\n\n            relationshipEntry?.Delete();\n            _partTracker.Remove(relationshipPath);\n\n            var path = part.Uri.ToPackagePath();\n\n            part.Entry.Delete();\n            _partTracker.Remove(path);\n        }\n\n        /// <summary>\n        /// Gets all package-wide relationships.\n        /// </summary>\n        /// <returns>A source of relationships.</returns>\n        public OpcRelationships Relationships\n        {\n            get\n            {\n                if (_relationships == null)\n                {\n                    _relationships = ConstructRelationships();\n                }\n\n                return _relationships;\n            }\n        }\n\n        /// <summary>\n        /// Flushes all changes of the package to disk. This automatically occurs when the <see cref=\"OpcPackage\"/> is disposed.\n        /// </summary>\n        public void Flush()\n        {\n            foreach (var part in _partTracker.Values)\n            {\n                if (part._relationships?.IsDirty == true)\n                {\n                    SaveRelationships(part._relationships);\n                    part._relationships.IsDirty = false;\n                }\n            }\n\n            if (_relationships?.IsDirty == true)\n            {\n                SaveRelationships(_relationships);\n                _relationships.IsDirty = false;\n            }\n\n            if (_contentTypes?.IsDirty == true)\n            {\n                var entry = Archive.GetEntry(CONTENT_TYPES_XML) ?? Archive.CreateEntry(CONTENT_TYPES_XML);\n                using (var stream = entry.Open())\n                {\n                    var newXml = _contentTypes.ToXml();\n                    stream.SetLength(0L);\n                    newXml.Save(stream, SaveOptions.None);\n                    _contentTypes.IsDirty = false;\n                }\n            }\n        }\n\n        private void SaveRelationships(OpcRelationships relationships)\n        {\n            if (!ContentTypes.Any(ct => string.Equals(ct.Extension, \"rels\", StringComparison.OrdinalIgnoreCase)))\n            {\n                ContentTypes.Add(new OpcContentType(\"rels\", OpcKnownMimeTypes.OpenXmlRelationship, OpcContentTypeMode.Default));\n            }\n\n            var path = relationships.DocumentUri.ToPackagePath();\n            var entry = Archive.GetEntry(path) ?? Archive.CreateEntry(path);\n\n            using (var stream = entry.Open())\n            {\n                stream.SetLength(0L);\n                var newXml = relationships.ToXml();\n                newXml.Save(stream, SaveOptions.None);\n            }\n        }\n\n        /// <summary>\n        /// Creates a signature builder for applying a digital signature to the package.\n        /// </summary>\n        /// <returns>A builder instance for configuring and applying a signature.</returns>\n        public OpcPackageSignatureBuilder CreateSignatureBuilder() => new OpcPackageSignatureBuilder(this);\n\n        /// <summary>\n        /// Enumerates over all of the signatures in the package.\n        /// </summary>\n        /// <returns>An enumerable collection of signatures in the package.</returns>\n        public IEnumerable<OpcSignature> GetSignatures()\n        {\n            var originFileRelationship = Relationships.FirstOrDefault(r => r.Type.Equals(OpcKnownUris.DigitalSignatureOrigin));\n\n            if (originFileRelationship == null)\n            {\n                yield break;\n            }\n\n            var originPart = GetPart(originFileRelationship.Target);\n\n            if (originPart == null)\n            {\n                yield break;\n            }\n\n            var signatureRelationships = originPart.Relationships.Where(r => r.Type.Equals(OpcKnownUris.DigitalSignatureSignature)).ToList();\n\n            foreach (var signatureRelationship in signatureRelationships)\n            {\n                var signaturePart = GetPart(signatureRelationship.Target);\n                if (signaturePart == null)\n                {\n                    continue;\n                }\n\n                yield return new OpcSignature(signaturePart);\n            }\n        }\n\n        private OpcContentTypes ConstructContentTypes()\n        {\n            var entry = Archive.GetEntry(CONTENT_TYPES_XML);\n            var readOnlyMode = _mode != OpcPackageFileMode.ReadWrite;\n\n            if (entry == null)\n            {\n                return new OpcContentTypes(readOnlyMode);\n            }\n            else\n            {\n                using (var stream = entry.Open())\n                {\n                    return new OpcContentTypes(XDocument.Load(stream, LoadOptions.PreserveWhitespace), readOnlyMode);\n                }\n            }\n        }\n\n        private OpcRelationships ConstructRelationships()\n        {\n            var entry = Archive.GetEntry(GLOBAL_RELATIONSHIPS);\n            var readOnlyMode = _mode != OpcPackageFileMode.ReadWrite;\n\n            if (entry == null)\n            {\n                var location = new Uri(BasePackageUri, GLOBAL_RELATIONSHIPS);\n\n                return new OpcRelationships(location, readOnlyMode);\n            }\n            else\n            {\n                var location = new Uri(BasePackageUri, entry.FullName);\n                using (var stream = entry.Open())\n                {\n                    return new OpcRelationships(location, XDocument.Load(stream, LoadOptions.PreserveWhitespace), readOnlyMode);\n                }\n            }\n        }\n\n        private static ZipArchiveMode GetZipModeFromOpcPackageMode(OpcPackageFileMode mode)\n        {\n            switch (mode)\n            {\n                case OpcPackageFileMode.Read:\n                    return ZipArchiveMode.Read;\n                case OpcPackageFileMode.ReadWrite:\n                    return ZipArchiveMode.Update;\n                default:\n                    throw new ArgumentException($\"Specified {nameof(OpcPackageFileMode)} is invalid.\", nameof(mode));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPackageFileMode.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Sets the mode of the package when opened.\n    /// </summary>\n    internal enum OpcPackageFileMode\n    {\n        /// <summary>\n        /// The package will be opened in read-only mode.\n        /// </summary>\n        Read,\n\n        /// <summary>\n        /// The package will be opened for reading and writing.\n        /// </summary>\n        ReadWrite\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPackageSignatureBuilder.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Xml;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// A builder to sign an OPC package.\n    /// </summary>\n    internal sealed class OpcPackageSignatureBuilder\n    {\n        private readonly OpcPackage _package;\n        private readonly List<OpcPart> _enqueuedParts;\n\n        internal OpcPackageSignatureBuilder(OpcPackage package)\n        {\n            _enqueuedParts = new List<OpcPart>();\n            _package = package;\n        }\n\n        /// <summary>\n        /// Enqueues a part that will be part of the package signature.\n        /// </summary>\n        /// <param name=\"part\">The part to enqueue.</param>\n        public void EnqueuePart(OpcPart part) => _enqueuedParts.Add(part);\n\n        /// <summary>\n        /// Dequeues a part from the signature builder. This file will not be part of the signature.\n        /// </summary>\n        /// <param name=\"part\">The part to dequeue.</param>\n        /// <returns>True if the file was dequeued, otherwise false.</returns>\n        public bool DequeuePart(OpcPart part) => _enqueuedParts.Remove(part);\n\n        /// <summary>\n        /// Enqueues a list of parts that are known for a standard configuration.\n        /// </summary>\n        /// <typeparam name=\"TPreset\">The type of preset to enqueue.</typeparam>\n        public void EnqueueNamedPreset<TPreset>() where TPreset : ISignatureBuilderPreset, new()\n        {\n            _enqueuedParts.AddRange(new TPreset().GetPartsForSigning(_package));\n        }\n\n        /// <summary>\n        /// Creates a signature from the enqueued parts.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration of properties used to create the signature.\n        /// See the documented of <see cref=\"SignConfigurationSet\"/> for more information.</param>\n        public OpcSignature Sign(SignConfigurationSet configuration)\n        {\n            var fileName = configuration.PublicCertificate.GetCertHashString() + \".psdsxs\";\n            var (allParts, signatureFile) = SignCore(fileName);\n            var signingContext = new SigningContext(configuration);\n            var fileManifest = OpcSignatureManifest.Build(signingContext, allParts);\n\n            var builder = new XmlSignatureBuilder(signingContext);\n            builder.SetFileManifest(fileManifest);\n\n            var result = builder.Build();\n            PublishSignature(result, signatureFile);\n\n            _package.Flush();\n\n            return new OpcSignature(signatureFile);\n        }\n\n        private static void PublishSignature(XmlDocument document, OpcPart signatureFile)\n        {\n            using (var copySignatureStream = signatureFile.Open())\n            {\n                copySignatureStream.SetLength(0L);\n                using (var xmlWriter = new XmlTextWriter(copySignatureStream, System.Text.Encoding.UTF8))\n                {\n                    //The .NET implementation of OPC used by Visual Studio does not tollerate \"white space\" nodes.\n                    xmlWriter.Formatting = Formatting.None;\n                    document.Save(xmlWriter);\n                }\n            }\n        }\n\n        private (HashSet<OpcPart> partsToSign, OpcPart signaturePart) SignCore(string signatureFileName)\n        {\n            var originFileUri = new Uri(\"package:///package/services/digital-signature/origin.psdor\", UriKind.Absolute);\n            var signatureUriRoot = new Uri(\"package:///package/services/digital-signature/xml-signature/\", UriKind.Absolute);\n            var originFileRelationship = _package.Relationships.FirstOrDefault(r => r.Type.Equals(OpcKnownUris.DigitalSignatureOrigin));\n\n            OpcPart originFile;\n            OpcPart signatureFile;\n            // Create the origin file and relationship to the origin file if needed.\n            if (originFileRelationship != null)\n            {\n                originFile = _package.GetPart(originFileRelationship.Target) ?? _package.CreatePart(originFileUri, OpcKnownMimeTypes.DigitalSignatureOrigin);\n            }\n            else\n            {\n                originFile = _package.GetPart(originFileUri) ?? _package.CreatePart(originFileUri, OpcKnownMimeTypes.DigitalSignatureOrigin);\n                _package.Relationships.Add(new OpcRelationship(originFile.Uri, OpcKnownUris.DigitalSignatureOrigin));\n            }\n\n            var signatureRelationship = originFile.Relationships.FirstOrDefault(r => r.Type.Equals(OpcKnownUris.DigitalSignatureSignature));\n\n            if (signatureRelationship != null)\n            {\n                signatureFile = _package.GetPart(signatureRelationship.Target) ?? _package.CreatePart(originFileUri, OpcKnownMimeTypes.DigitalSignatureSignature);\n            }\n            else\n            {\n                var target = new Uri(signatureUriRoot, signatureFileName);\n                signatureFile = _package.GetPart(target) ?? _package.CreatePart(target, OpcKnownMimeTypes.DigitalSignatureSignature);\n                originFile.Relationships.Add(new OpcRelationship(target, OpcKnownUris.DigitalSignatureSignature));\n            }\n\n            _package.Flush();\n\n            var allParts = new HashSet<OpcPart>(_enqueuedParts)\n            {\n                originFile,\n            };\n\n            var tempPart = _package.GetPart(_package.Relationships.DocumentUri);\n            if (tempPart != null)\n            {\n                allParts.Add(tempPart);\n            }\n\n            tempPart = _package.GetPart(originFile.Relationships.DocumentUri);\n            if (tempPart != null)\n            {\n                allParts.Add(tempPart);\n            }\n\n            return (allParts, signatureFile);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPackageTimestampBuilder.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Xml;\nusing System.Xml.Linq;\nusing Sign.Core.Timestamp;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// A builder for adding timestamps to a package.\n    /// </summary>\n    internal sealed class OpcPackageTimestampBuilder\n    {\n        private readonly OpcPart _part;\n\n        internal OpcPackageTimestampBuilder(OpcPart part)\n        {\n            _part = part;\n            Timeout = TimeSpan.FromSeconds(30);\n        }\n\n        /// <summary>\n        /// Gets or sets the timeout for signing the package.\n        /// The default is 30 earth seconds.\n        /// </summary>\n        public TimeSpan Timeout { get; set; }\n\n        /// <summary>\n        /// Signs the package with a timestamp.\n        /// </summary>\n        /// <param name=\"timestampServer\">The URI of the timestamp server.</param>\n        /// <param name=\"timestampAlgorithm\">The hash algorithm to timestamp with.</param>\n        /// <returns>A result of the timestamp operation.</returns>\n        public async Task<TimestampResult> SignAsync(Uri timestampServer, HashAlgorithmName timestampAlgorithm)\n        {\n            if (timestampServer == null)\n            {\n                throw new ArgumentNullException(nameof(timestampServer));\n            }\n\n            if (!timestampServer.IsAbsoluteUri)\n            {\n                throw new ArgumentException(\"The timestamp server must be an absolute URI.\", nameof(timestampServer));\n            }\n\n            var nonce = TimestampNonce.Generate();\n            var (document, signature) = GetSignatureToTimestamp(_part);\n            var (result, timestamp) = await TimestampBuilder.RequestTimestamp(timestampServer, timestampAlgorithm, nonce, Timeout, signature);\n\n            if (result == TimestampResult.Success)\n            {\n                ApplyTimestamp(document, _part, timestamp);\n            }\n\n            return result;\n        }\n\n        private static (XDocument document, byte[] signature) GetSignatureToTimestamp(OpcPart signaturePart)\n        {\n            XNamespace xmlDSigNamespace = OpcKnownUris.XmlDSig.AbsoluteUri;\n            using (var signatureStream = signaturePart.Open())\n            {\n                var doc = XDocument.Load(signatureStream);\n                var signature = doc.Element(xmlDSigNamespace + \"Signature\")?.Element(xmlDSigNamespace + \"SignatureValue\")?.Value?.Trim();\n\n                return (doc, signature != null ? Convert.FromBase64String(signature) : throw new NullReferenceException(\"Unable to acquire Xml signature value.\"));\n            }\n        }\n\n        private static void ApplyTimestamp(XDocument originalSignatureDocument, OpcPart signaturePart, byte[]? timestampSignature)\n        {\n            XNamespace xmlDSigNamespace = OpcKnownUris.XmlDSig.AbsoluteUri;\n            XNamespace xmlSignatureNamespace = OpcKnownUris.XmlDigitalSignature.AbsoluteUri;\n            var document = new XDocument(originalSignatureDocument);\n            var signature = new XElement(xmlDSigNamespace + \"Object\",\n                new XElement(xmlSignatureNamespace + \"TimeStamp\", new XAttribute(\"Id\", \"idSignatureTimestamp\"),\n                    new XElement(xmlSignatureNamespace + \"Comment\", \"Timestamp got from the time stamp server\"),\n                    new XElement(xmlSignatureNamespace + \"EncodedTime\", Convert.ToBase64String(timestampSignature ?? Array.Empty<byte>()))\n                )\n            );\n\n            document.Element(xmlDSigNamespace + \"Signature\")?.Add(signature);\n            using (var copySignatureStream = signaturePart.Open())\n            {\n                using (var xmlWriter = new XmlTextWriter(copySignatureStream, System.Text.Encoding.UTF8))\n                {\n                    //The .NET implementation of OPC used by Visual Studio does not tollerate \"white space\" nodes.\n                    xmlWriter.Formatting = Formatting.None;\n                    document.Save(xmlWriter);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPart.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing System.Xml.Linq;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Represents a part inside of a package.\n    /// </summary>\n    internal sealed class OpcPart : IEquatable<OpcPart>\n    {\n        internal OpcRelationships? _relationships;\n        private readonly OpcPackageFileMode _mode;\n        private readonly string _path;\n\n        internal OpcPart(OpcPackage package, string path, ZipArchiveEntry entry, OpcPackageFileMode mode)\n        {\n            Uri = new Uri(OpcPackage.BasePackageUri, path);\n            Package = package;\n            _path = path;\n            Entry = entry;\n            _mode = mode;\n        }\n\n        internal OpcPackage Package { get; }\n\n        internal ZipArchiveEntry Entry { get; }\n\n\n        /// <summary>\n        /// A package URI of the current part.\n        /// </summary>\n        public Uri Uri { get; }\n\n        /// <summary>\n        /// The collection of relationships for this part.\n        /// </summary>\n        public OpcRelationships Relationships\n        {\n            get\n            {\n                if (_relationships == null)\n                {\n                    _relationships = ConstructRelationships();\n                }\n\n                return _relationships;\n            }\n        }\n\n        /// <summary>\n        /// Gets a MIME content type of the current part.\n        /// </summary>\n        public string ContentType\n        {\n            get\n            {\n                var extension = Path.GetExtension(_path)?.TrimStart('.');\n\n                return Package.ContentTypes.FirstOrDefault(ct => string.Equals(ct.Extension, extension, StringComparison.OrdinalIgnoreCase))?.ContentType ?? OpcKnownMimeTypes.OctetString;\n            }\n        }\n\n        private string GetRelationshipFilePath()\n        {\n            var pathDirectory = Path.GetDirectoryName(_path);\n\n            if (pathDirectory == null)\n            {\n                throw new DirectoryNotFoundException($\"Cannot access parent directory of {_path}\");\n            }\n\n            return Path.Combine(pathDirectory, \"_rels/\" + Path.GetFileName(_path) + \".rels\").Replace('\\\\', '/');\n        }\n\n        private OpcRelationships ConstructRelationships()\n        {\n            var path = GetRelationshipFilePath();\n            var entry = Package.Archive.GetEntry(path);\n            var readOnlyMode = _mode != OpcPackageFileMode.ReadWrite;\n            var location = new Uri(OpcPackage.BasePackageUri, path);\n            if (entry == null)\n            {\n                return new OpcRelationships(location, readOnlyMode);\n            }\n            else\n            {\n                using (var stream = entry.Open())\n                {\n                    return new OpcRelationships(location, XDocument.Load(stream, LoadOptions.PreserveWhitespace), readOnlyMode);\n                }\n            }\n        }\n\n\n        /// <summary>\n        /// Opens the part's contents as a stream.\n        /// </summary>\n        /// <returns>A stream of the part's contents.</returns>\n        public Stream Open() => Entry.Open();\n\n        /// <inheritdoc />\n        public bool Equals(OpcPart? other) => other != null && Uri.Equals(other.Uri);\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => obj is OpcPart part && Equals(part);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Uri.GetHashCode();\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPartDigest.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal class OpcPartDigest\n    {\n        public Uri ReferenceUri { get; }\n        public Uri DigestAlgorithmIdentifier { get; }\n        public byte[] Digest { get; }\n\n        public OpcPartDigest(Uri referenceUri, Uri digestAlgorithmIdentifer, byte[] digest)\n        {\n            ReferenceUri = referenceUri;\n            DigestAlgorithmIdentifier = digestAlgorithmIdentifer;\n            Digest = digest;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcPartDigestProcessor.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    internal static class OpcPartDigestProcessor\n    {\n        public static (byte[] digest, Uri identifier) Digest(OpcPart part, HashAlgorithmName algorithmName)\n        {\n            var info = new HashAlgorithmInfo(algorithmName);\n\n            using (var hashAlgorithm = info.Create())\n            {\n                using (var partStream = part.Open())\n                {\n                    var digest = hashAlgorithm.ComputeHash(partStream);\n\n                    return (digest, info.XmlDSigIdentifier);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcRelationships.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections;\nusing System.Security.Cryptography;\nusing System.Xml.Linq;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// A class that represents a part relationship in a package.\n    /// </summary>\n    internal sealed class OpcRelationship : IEquatable<OpcRelationship>\n    {\n        /// <summary>\n        /// The target part for the relationship.\n        /// </summary>\n        public Uri Target { get; }\n\n        /// <summary>\n        /// A unique identifier for the part.\n        /// </summary>\n        public string? Id { get; internal set; }\n\n        /// <summary>\n        /// The type of the part.\n        /// </summary>\n        public Uri Type { get; }\n\n        /// <summary>\n        /// Creates a new relationship for a part.\n        /// </summary>\n        /// <param name=\"target\">The package relative URI for the target part.</param>\n        /// <param name=\"id\">A unique identifier for a part.</param>\n        /// <param name=\"type\">A URI indicating the type of the part.</param>\n        public OpcRelationship(Uri target, string id, Uri type)\n        {\n            Target = target;\n            Id = id;\n            Type = type;\n        }\n\n\n        /// <summary>\n        /// Creates a new relationship for a part.\n        /// </summary>\n        /// <param name=\"target\">The package relative URI for the target part.</param>\n        /// <param name=\"type\">A URI indicating the type of the part.</param>\n        public OpcRelationship(Uri target, Uri type)\n        {\n            Target = target;\n            Type = type;\n        }\n\n\n        /// <summary>\n        /// Compares two part relationships for equality.\n        /// </summary>\n        /// <param name=\"other\">The <see cref=\"OpcRelationship\"/> to compare against.</param>\n        /// <returns>True if the relationships are equal, false otherwise.</returns>\n        public bool Equals(OpcRelationship? other) => other != null && Target == other.Target && Type == other.Type && Id == other.Id;\n\n        /// <summary>\n        /// Compares against an object for equality.\n        /// </summary>\n        /// <param name=\"obj\">The object to compare against.</param>\n        /// <returns>True if the objects are equal, false otherwise.</returns>\n        public override bool Equals(object? obj) => obj is OpcRelationship rel && Equals(rel);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Target.GetHashCode() ^ Type.GetHashCode();\n    }\n\n\n    /// <summary>\n    /// A class for a collection of <see cref=\"OpcRelationship\"/>.\n    /// </summary>\n    internal sealed class OpcRelationships : IList<OpcRelationship>\n    {\n        private static readonly XNamespace _opcRelationshipNamespace = \"http://schemas.openxmlformats.org/package/2006/relationships\";\n        private readonly List<OpcRelationship> _relationships = new List<OpcRelationship>();\n\n\n        internal OpcRelationships(Uri documentUri, XDocument? document, bool isReadOnly)\n        {\n            IsReadOnly = isReadOnly;\n            DocumentUri = documentUri;\n            var relationships = document?.Root?.Elements(_opcRelationshipNamespace + \"Relationship\");\n\n            if (relationships == null)\n            {\n                return;\n            }\n\n            foreach (var relationship in relationships)\n            {\n                var target = relationship.Attribute(\"Target\")?.Value;\n                var id = relationship.Attribute(\"Id\")?.Value;\n                var type = relationship.Attribute(\"Type\")?.Value;\n\n                if (type == null || id == null || target == null)\n                {\n                    continue;\n                }\n\n                _relationships.Add(new OpcRelationship(new Uri(target, UriKind.Relative), id,\n                    new Uri(type, UriKind.RelativeOrAbsolute)));\n            }\n        }\n\n        internal OpcRelationships(Uri documentUri, bool isReadOnly)\n        {\n            IsReadOnly = isReadOnly;\n            DocumentUri = documentUri;\n        }\n\n\n        /// <summary>\n        /// Creates an <see cref=\"XDocument\"/> for the currect collection of relationships.\n        /// </summary>\n        /// <returns>An <see cref=\"XDocument\"/> instance for all relationships in the collection.</returns>\n        public XDocument ToXml()\n        {\n            var document = new XDocument();\n            var root = new XElement(_opcRelationshipNamespace + \"Relationships\");\n\n            foreach (var relationship in _relationships)\n            {\n                var element = new XElement(_opcRelationshipNamespace + \"Relationship\");\n                element.SetAttributeValue(\"Target\", relationship.Target.ToQualifiedPath());\n                element.SetAttributeValue(\"Id\", relationship.Id);\n                element.SetAttributeValue(\"Type\", relationship.Type);\n                root.Add(element);\n            }\n\n            document.Add(root);\n\n            return document;\n        }\n\n\n        /// <summary>\n        /// Gets the number of relationships in the collection.\n        /// </summary>\n        public int Count => _relationships.Count;\n\n        /// <summary>\n        /// True if the collection is read only, otherwise false.\n        /// </summary>\n        public bool IsReadOnly { get; }\n\n        internal Uri DocumentUri { get; }\n\n        /// <summary>\n        /// Gets an <see cref=\"OpcRelationship\"/> at a given index.\n        /// </summary>\n        /// <param name=\"index\">The index of the relationship.</param>\n        /// <returns>An <see cref=\"OpcRelationship\"/>.</returns>\n        public OpcRelationship this[int index]\n        {\n            get => _relationships[index];\n            set\n            {\n                AssertNotReadOnly();\n                IsDirty = true;\n                AssignRelationshipId(value);\n                _relationships[index] = value;\n            }\n        }\n\n        internal bool IsDirty { get; set; }\n\n\n        /// <summary>\n        /// Gets the index of an <see cref=\"OpcRelationship\"/>.\n        /// </summary>\n        /// <param name=\"item\">The instance of <see cref=\"OpcRelationship\"/> to retreive the index.</param>\n        /// <returns>The index of the relatnship, or <c>-1</c> if the relationship is not in this collection.</returns>\n        public int IndexOf(OpcRelationship item) => _relationships.IndexOf(item);\n\n        /// <summary>\n        /// Inserts an <see cref=\"OpcRelationship\"/> at a specific index.\n        /// </summary>\n        /// <param name=\"index\">The index to insert the <see cref=\"OpcRelationship\"/> at.</param>\n        /// <param name=\"item\">The relationship to insert.</param>\n        public void Insert(int index, OpcRelationship item)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            AssignRelationshipId(item);\n            _relationships.Insert(index, item);\n        }\n\n        /// <summary>\n        /// Removes an <see cref=\"OpcRelationship\"/> at a specific index.\n        /// </summary>\n        /// <param name=\"index\">The index to remove the <see cref=\"OpcRelationship\"/> at.</param>\n        public void RemoveAt(int index)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _relationships.RemoveAt(index);\n        }\n\n        /// <summary>\n        /// Adds a relationship to the collection.\n        /// </summary>\n        /// <param name=\"item\">The relationship to add.</param>\n        public void Add(OpcRelationship item)\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            AssignRelationshipId(item);\n            _relationships.Add(item);\n        }\n\n        /// <summary>\n        /// Clears the list of relationships.\n        /// </summary>\n        public void Clear()\n        {\n            AssertNotReadOnly();\n            IsDirty = true;\n            _relationships.Clear();\n        }\n\n\n        /// <summary>\n        /// Determines if the collections contains a relationship.\n        /// </summary>\n        /// <param name=\"item\">The item to determine if it exists in the current collection.</param>\n        /// <returns>True if the item is in the collection, otherwise false.</returns>\n        public bool Contains(OpcRelationship item) => _relationships.Contains(item);\n\n        /// <inheritdoc />\n        public void CopyTo(OpcRelationship[] array, int arrayIndex) => _relationships.CopyTo(array, arrayIndex);\n\n        /// <summary>\n        /// Removes a relationship from the collection.\n        /// </summary>\n        /// <param name=\"item\">The item to remove.</param>\n        /// <returns>True if the item was removed, otherwise false.</returns>\n        public bool Remove(OpcRelationship item)\n        {\n            AssertNotReadOnly();\n\n            return IsDirty = _relationships.Remove(item);\n        }\n\n        /// <inheritdoc />\n        public IEnumerator<OpcRelationship> GetEnumerator() => _relationships.GetEnumerator();\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        private void AssertNotReadOnly()\n        {\n            if (IsReadOnly)\n            {\n                throw new InvalidOperationException(\"Cannot update relationships in a read only package. Please open the package in write mode.\");\n            }\n        }\n\n        private void AssignRelationshipId(OpcRelationship relationship)\n        {\n            if (!string.IsNullOrWhiteSpace(relationship.Id))\n            {\n                return;\n            }\n\n#if NET\n            Span<byte> data = stackalloc byte[sizeof(uint)];\n            Span<char> buffer = stackalloc char[9];\n            buffer[0] = 'R';\n\n            while (true)\n            {\n                RandomNumberGenerator.Fill(data);\n                if (!HexHelpers.TryHexEncode(data, buffer.Slice(1)))\n                {\n                    throw new InvalidOperationException(\"Buffer is too small.\");\n                }\n                var id = buffer.ToString();\n                if (_relationships.Any(r => r.Id == id))\n                {\n                    continue;\n                }\n                relationship.Id = id;\n                break;\n            }\n#else\n            using (var rng = RandomNumberGenerator.Create())\n            {\n                var data = new byte[4];\n                Span<char> buffer = stackalloc char[9];\n                buffer[0] = 'R';\n                while(true)\n                {\n                    rng.GetBytes(data);\n                    if (!HexHelpers.TryHexEncode(data, buffer.Slice(1)))\n                    {\n                        throw new InvalidOperationException(\"Buffer is too small.\");\n                    }\n                    var id = buffer.ToString();\n                    if (_relationships.Any(r ? => r.Id == id))\n                    {\n                        continue;\n                    }\n                    relationship.Id = id;\n                    break;\n                }\n            }\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcSignature.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Represents an OPC signature.\n    /// </summary>\n    /// <remarks>\n    /// This type cannot be directly created. To create a signature on a package, use <see cref=\"OpcPackage.CreateSignatureBuilder\" />.\n    /// </remarks>\n    internal sealed class OpcSignature\n    {\n        private readonly OpcPart _signaturePart;\n        private bool _detached;\n\n        internal OpcSignature(OpcPart signaturePart)\n        {\n            _detached = false;\n            _signaturePart = signaturePart;\n        }\n\n        /// <summary>\n        /// Gets the part in the package for this signatures.\n        /// </summary>\n        public OpcPart? Part => _detached ? null : _signaturePart;\n\n        /// <summary>\n        /// Creates a builder to timestamp the existing signature.\n        /// </summary>\n        /// <returns>An <see cref=\"OpcPackageTimestampBuilder\"/> that allows building and configuring timestamps.</returns>\n        public OpcPackageTimestampBuilder CreateTimestampBuilder()\n        {\n            if (_detached)\n            {\n                throw new InvalidOperationException(\"Cannot timestamp a signature that has been removed.\");\n            }\n\n            return new OpcPackageTimestampBuilder(_signaturePart);\n        }\n\n\n        /// <summary>\n        /// Removes the signature from the package.\n        /// </summary>\n        public void Remove()\n        {\n            if (_detached)\n            {\n                return;\n            }\n\n            _detached = true;\n            var originFileRelationship = _signaturePart.Package.Relationships.FirstOrDefault(r => r.Type.Equals(OpcKnownUris.DigitalSignatureOrigin));\n\n            if (originFileRelationship == null)\n            {\n                // This shouldn't ever happen. This means we have a signature instance but no metadata connecting it to the package.\n                // all we can do at this point is delete the part.\n                _signaturePart.Package.RemovePart(_signaturePart);\n\n                return;\n            }\n\n            var originFile = _signaturePart.Package.GetPart(originFileRelationship.Target);\n\n            if (originFile == null)\n            {\n                // This shouldn't happen either. The package has a relationship to a non-existing origin file. Clean up the\n                // signature part and the relationship.\n                _signaturePart.Package.RemovePart(_signaturePart);\n                _signaturePart.Package.Relationships.Remove(originFileRelationship);\n\n                return;\n            }\n\n            var signatureRelationships = originFile.Relationships.Where(\n                r => r.Target == _signaturePart.Uri.ToQualifiedUri() &&\n                     r.Type == OpcKnownUris.DigitalSignatureSignature\n                ).ToList();\n\n            if (signatureRelationships.Count == 0)\n            {\n                // Another case that shouldn't happen. There was an origin file, but no relationship to this signature.\n                // Remove the signature. We don't remove the origin file relationship because there could be other valid\n                // relationships at this point.\n                _signaturePart.Package.RemovePart(_signaturePart);\n\n                return;\n            }\n\n            // This is the valid scenario. We need to remove the signature part and the origin relationship to this\n            // signature. If there are no more signatures after this one is removed, then we remove the origin file\n            // and the package relationship to the origin.\n            // Note that it is technically incorrect for the origin file to have more than one reference to this signature\n            // with the same type, but if it did happen, we remove all of them.\n\n            // Remove relationships to this signature.\n            foreach (var signatureRelationship in signatureRelationships)\n            {\n                originFile.Relationships.Remove(signatureRelationship);\n            }\n\n            // If we're empty now, remove the origin file and the package relationship to the origin.\n            if (originFile.Relationships.Count == 0)\n            {\n                _signaturePart.Package.RemovePart(originFile);\n                _signaturePart.Package.Relationships.Remove(originFileRelationship);\n            }\n            _signaturePart.Package.RemovePart(_signaturePart);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/OpcSignatureManifest.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    internal class OpcSignatureManifest\n    {\n        private readonly List<OpcPartDigest> _digests;\n\n        private OpcSignatureManifest(List<OpcPartDigest> digests)\n        {\n            _digests = digests;\n        }\n\n        public static OpcSignatureManifest Build(ISigningContext context, HashSet<OpcPart> parts)\n        {\n            var digests = new List<OpcPartDigest>(parts.Count);\n\n            foreach (var part in parts)\n            {\n                var (digest, identifier) = OpcPartDigestProcessor.Digest(part, context.FileDigestAlgorithmName);\n                var builder = new UriBuilder(part.Uri)\n                {\n                    Query = \"ContentType=\" + part.ContentType\n                };\n                digests.Add(new OpcPartDigest(builder.Uri, identifier, digest));\n            }\n\n            return new OpcSignatureManifest(digests);\n        }\n\n        public IReadOnlyList<OpcPartDigest> Manifest => _digests;\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/SignConfigurationSet.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// A configuration set for a signing operation.\n    /// </summary>\n    internal sealed class SignConfigurationSet\n    {\n        /// <summary>\n        /// Creates a new instance of the <see cref=\"SignConfigurationSet\"/>.\n        /// </summary>\n        /// <param name=\"fileDigestAlgorithm\">The <see cref=\"HashAlgorithmName\"/> used to digest files.</param>\n        /// <param name=\"signatureDigestAlgorithm\">The <see cref=\"HashAlgorithmName\"/> used in signatures.</param>\n        /// <param name=\"signingKey\">An <see cref=\"AsymmetricAlgorithm\"/> with a private key that is used to perform signing operations.</param>\n        /// <param name=\"publicCertificate\">An <see cref=\"X509Certificate2\"/> that contains the public key and certificate used to embed in the signature.</param>\n        public SignConfigurationSet(HashAlgorithmName fileDigestAlgorithm, HashAlgorithmName signatureDigestAlgorithm, AsymmetricAlgorithm signingKey, X509Certificate2 publicCertificate)\n        {\n            FileDigestAlgorithm = fileDigestAlgorithm;\n            SignatureDigestAlgorithm = signatureDigestAlgorithm;\n            SigningKey = signingKey;\n            PublicCertificate = publicCertificate;\n        }\n\n        /// <summary>\n        /// The <see cref=\"HashAlgorithmName\"/> used to digest files.\n        /// </summary>\n        public HashAlgorithmName FileDigestAlgorithm { get; }\n\n        /// <summary>\n        /// The <see cref=\"HashAlgorithmName\"/> used in signatures.\n        /// </summary>\n        public HashAlgorithmName SignatureDigestAlgorithm { get; }\n\n        /// <summary>\n        /// An <see cref=\"AsymmetricAlgorithm\"/> with a private key that is used to perform signing operations.\n        /// </summary>\n        public AsymmetricAlgorithm SigningKey { get; }\n\n        /// <summary>\n        /// An <see cref=\"X509Certificate2\"/> that contains the public key and certificate used to embed in the signature.\n        /// </summary>\n        public X509Certificate2 PublicCertificate { get; }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/SignatureAlgorithmTranslator.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core\n{\n    internal static class SignatureAlgorithmTranslator\n    {\n        public static Uri SignatureAlgorithmToXmlDSigUri(SigningAlgorithm signatureAlgorithm, HashAlgorithmName hashAlgorithmName)\n        {\n            switch (signatureAlgorithm)\n            {\n                case SigningAlgorithm.RSA when hashAlgorithmName.Name == HashAlgorithmName.SHA256.Name:\n                    return OpcKnownUris.SignatureAlgorithms.RsaSHA256;\n                case SigningAlgorithm.RSA when hashAlgorithmName.Name == HashAlgorithmName.SHA384.Name:\n                    return OpcKnownUris.SignatureAlgorithms.RsaSHA384;\n                case SigningAlgorithm.RSA when hashAlgorithmName.Name == HashAlgorithmName.SHA512.Name:\n                    return OpcKnownUris.SignatureAlgorithms.RsaSHA512;\n                default:\n                    throw new NotSupportedException(\"The algorithm specified is not supported.\");\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/SigningAlgorithm.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Indicates a signing algorithm.\n    /// </summary>\n    internal enum SigningAlgorithm\n    {\n        /// <summary>\n        /// The signing algorithm is unknown.\n        /// </summary>\n        Unknown = 0,\n\n        /// <summary>\n        /// The signing algorithm is RSA.\n        /// </summary>\n        RSA,\n    }\n}"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/SigningContext.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// A signing context used for signing packages with Azure Key Vault Keys.\n    /// </summary>\n    internal sealed class SigningContext : ISigningContext\n    {\n        private readonly SignConfigurationSet _configuration;\n\n        /// <summary>\n        /// Creates a new signing context.\n        /// </summary>\n        public SigningContext(SignConfigurationSet configuration)\n        {\n            ContextCreationTime = DateTimeOffset.Now;\n            _configuration = configuration;\n        }\n\n        /// <summary>\n        /// Gets the date and time that this context was created.\n        /// </summary>\n        public DateTimeOffset ContextCreationTime { get; }\n\n        /// <summary>\n        /// Gets the file digest algorithm.\n        /// </summary>\n        public HashAlgorithmName FileDigestAlgorithmName => _configuration.FileDigestAlgorithm;\n\n        /// <summary>\n        /// Gets the certificate and public key used to validate the signature.\n        /// </summary>\n        public X509Certificate2 Certificate => _configuration.PublicCertificate;\n\n        /// <summary>\n        /// Gets the signature algorithm.\n        /// </summary>\n        public SigningAlgorithm SignatureAlgorithm\n        {\n            get\n            {\n                switch (_configuration.SigningKey)\n                {\n                    case RSA _: return SigningAlgorithm.RSA;\n                    default: return SigningAlgorithm.Unknown;\n                }\n            }\n        }\n\n\n        /// <summary>\n        /// Gets the XmlDSig identifier for the configured algorithm.\n        /// </summary>\n        public Uri XmlDSigIdentifier => SignatureAlgorithmTranslator.SignatureAlgorithmToXmlDSigUri(SignatureAlgorithm, _configuration.SignatureDigestAlgorithm);\n\n\n        /// <summary>\n        /// Signs a digest.\n        /// </summary>\n        /// <param name=\"digest\">The digest to sign.</param>\n        /// <returns>The signature of the digest.</returns>\n        public byte[] SignDigest(byte[] digest)\n        {\n            switch (_configuration.SigningKey)\n            {\n                case RSA rsa:\n                    // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                    return rsa.SignHash(digest, _configuration.SignatureDigestAlgorithm, RSASignaturePadding.Pkcs1);\n                case ECDsa ecdsa:\n                    return ecdsa.SignHash(digest);\n                default:\n                    throw new InvalidOperationException(Resources.VSIXSignToolUnknownSigningAlgorithm);\n            }\n        }\n\n        /// <summary>\n        /// Verifies a digest is valid given a signature.\n        /// </summary>\n        /// <param name=\"digest\">The digest to validate.</param>\n        /// <param name=\"signature\">The signature to validate with.</param>\n        /// <returns></returns>\n        public bool VerifyDigest(byte[] digest, byte[] signature)\n        {\n\n            switch (SignatureAlgorithm)\n            {\n                case SigningAlgorithm.RSA:\n                    using (var publicKey = Certificate.GetRSAPublicKey())\n                    {\n                        // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                        return publicKey != null ? publicKey.VerifyHash(digest, signature, _configuration.SignatureDigestAlgorithm, RSASignaturePadding.Pkcs1) : false;\n                    }\n                default:\n                    throw new InvalidOperationException(Resources.VSIXSignToolUnknownSigningAlgorithm);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Timestamp/TimestampBuilder.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Timestamp\n{\n    internal static partial class TimestampBuilder\n    {\n        public static Task<(TimestampResult, byte[]?)> RequestTimestamp(Uri timestampUri, HashAlgorithmName timestampAlgorithm, TimestampNonce nonce, TimeSpan timeout, byte[] content)\n        {\n            var info = new HashAlgorithmInfo(timestampAlgorithm);\n            byte[] digest;\n            using (var hash = info.Create())\n            {\n                digest = hash.ComputeHash(content);\n            }\n\n            return SubmitTimestampRequest(timestampUri, info.Oid, nonce, timeout, digest);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Timestamp/TimestampBuilder.netcoreapp.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Net;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\n\nnamespace Sign.Core.Timestamp\n{\n    static partial class TimestampBuilder\n    {\n        private static async Task<(TimestampResult, byte[]?)> SubmitTimestampRequest(Uri timestampUri, Oid digestOid, TimestampNonce nonce, TimeSpan timeout, byte[] digest)\n        {\n            var timestampRequest = Rfc3161TimestampRequest.CreateFromHash(digest, digestOid, nonce: nonce.Nonce, requestSignerCertificates: true);\n            var encodedRequest = timestampRequest.Encode();\n            var client = new HttpClient\n            {\n                Timeout = timeout\n            };\n\n            var content = new ByteArrayContent(encodedRequest);\n\n            content.Headers.Add(\"Content-Type\", \"application/timestamp-query\");\n\n            var post = await client.PostAsync(timestampUri, content);\n\n            if (post.StatusCode != HttpStatusCode.OK)\n            {\n                return (TimestampResult.Failed, null);\n            }\n\n            var responseBytes = await post.Content.ReadAsByteArrayAsync();\n            var token = timestampRequest.ProcessResponse(responseBytes, out _);\n            var tokenInfo = token.AsSignedCms().Encode();\n\n            return (TimestampResult.Success, tokenInfo);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Timestamp/TimestampNonce.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Timestamp\n{\n    internal readonly struct TimestampNonce\n    {\n        public ReadOnlyMemory<byte> Nonce { get; }\n\n        public TimestampNonce(ReadOnlyMemory<byte> nonce)\n        {\n            Nonce = nonce;\n        }\n\n        public static TimestampNonce Generate(int nonceSize = 32)\n        {\n            var nonce = new byte[nonceSize];\n#if NET\n            RandomNumberGenerator.Fill(nonce);\n#else\n            using (var rng = RandomNumberGenerator.Create())\n            {\n                rng.GetBytes(nonce);\n            }\n#endif\n            //The nonce is technically an integer. Some timestamp servers may not like a \"negative\" nonce. Clear the sign bit so it's positive.\n            //That loses one bit of entropy, however is well within the security boundary of a properly sized nonce. Authenticode doesn't even use\n            //a nonce.\n            nonce[nonce.Length - 1] &= 0b01111111;\n            return new TimestampNonce(nonce);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/Timestamp/TimestampResult.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Timestamp\n{\n    /// <summary>\n    /// Indicates the status of the timestamp operation.\n    /// </summary>\n    internal enum TimestampResult\n    {\n        /// <summary>\n        /// The timestamp operation was a success.\n        /// </summary>\n        Success = 1,\n\n        /// <summary>\n        /// The package could not be timestamped because it does not have an existing signature.\n        /// </summary>\n        PackageNotSigned = 2,\n\n        /// <summary>\n        /// The timestamp operation failed.\n        /// </summary>\n        Failed = 3\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/UriHelpers.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// Extensions for working with URIs in OPC packages.\n    /// </summary>\n    internal static class UriHelpers\n    {\n        private static readonly Uri _packageBaseUri = new Uri(\"package:///\", UriKind.Absolute);\n        private static readonly Uri _rootedPackageBaseUri = new Uri(\"package:\", UriKind.Absolute);\n\n\n        /// <summary>\n        /// Converts a package URI to a path within the package zip file.\n        /// </summary>\n        /// <param name=\"partUri\">The URI to convert.</param>\n        /// <returns>A string to the path in a zip file.</returns>\n        public static string ToPackagePath(this Uri partUri)\n        {\n            var absolute = partUri.IsAbsoluteUri ? partUri : new Uri(_packageBaseUri, partUri);\n            var pathUri = new Uri(absolute.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped), UriKind.Absolute);\n            var resolved = _packageBaseUri.MakeRelativeUri(pathUri);\n\n            return resolved.ToString();\n        }\n\n        /// <summary>\n        /// Converts a package URI to a qualified path within the package zip file.\n        /// </summary>\n        /// <param name=\"partUri\">The URI to convert.</param>\n        /// <returns>A string to the qualified path in the zip file.</returns>\n        public static string ToQualifiedPath(this Uri partUri)\n        {\n            var absolute = partUri.IsAbsoluteUri ? partUri : new Uri(_rootedPackageBaseUri, partUri);\n            var pathUri = new Uri(absolute.GetComponents(UriComponents.SchemeAndServer | UriComponents.PathAndQuery, UriFormat.Unescaped), UriKind.Absolute);\n            var resolved = _rootedPackageBaseUri.MakeRelativeUri(pathUri);\n\n            return resolved.ToString();\n        }\n\n\n        /// <summary>\n        /// Converts a package URI to a qualified relative path URI within the package zip file.\n        /// </summary>\n        /// <param name=\"partUri\">The URI to convert.</param>\n        /// <returns>A URI to the qualified path in the zip file.</returns>\n        public static Uri ToQualifiedUri(this Uri partUri)\n        {\n            var absolute = partUri.IsAbsoluteUri ? partUri : new Uri(_rootedPackageBaseUri, partUri);\n            var pathUri = new Uri(absolute.GetComponents(UriComponents.SchemeAndServer | UriComponents.PathAndQuery, UriFormat.Unescaped), UriKind.Absolute);\n\n            return _rootedPackageBaseUri.MakeRelativeUri(pathUri);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/VSIXSignatureBuilderPreset.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core\n{\n    /// <summary>\n    /// The preset for VSIX files.\n    /// </summary>\n    internal sealed class VSIXSignatureBuilderPreset : ISignatureBuilderPreset\n    {\n        IEnumerable<OpcPart> ISignatureBuilderPreset.GetPartsForSigning(OpcPackage package)\n        {\n            var existingSignatures = package.GetSignatures().ToList();\n            foreach (var part in package.GetParts())\n            {\n                if (existingSignatures.All(existing => Uri.Compare(part.Uri, existing.Part?.Uri, UriComponents.Path, UriFormat.Unescaped, StringComparison.Ordinal) != 0))\n                {\n                    yield return part;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool/XmlSignatureBuilder.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Security.Cryptography.Xml;\nusing System.Xml;\n\nnamespace Sign.Core\n{\n    internal class XmlSignatureBuilder\n    {\n        private readonly XmlDocument _document;\n        private readonly ISigningContext _signingContext;\n        private readonly XmlElement _signatureElement;\n        private XmlElement? _objectElement;\n\n\n        /// <summary>\n        /// Creates a new signature with the correct namespace and empty root <c>Signature</c> element.\n        /// </summary>\n        internal XmlSignatureBuilder(ISigningContext signingContext)\n        {\n            _signingContext = signingContext;\n            _document = new XmlDocument();\n            var manager = new XmlNamespaceManager(_document.NameTable);\n            manager.AddNamespace(prefix: \"\", OpcKnownUris.XmlDSig.AbsoluteUri);\n            _signatureElement = CreateDSigElement(\"Signature\");\n        }\n\n        private XmlElement CreateDSigElement(string name) => _document.CreateElement(name, OpcKnownUris.XmlDSig.AbsoluteUri);\n\n        public XmlDocument Build()\n        {\n            if (_objectElement == null)\n            {\n                throw new InvalidOperationException(\"A manifest has not been set on the builder.\");\n            }\n\n            XmlElement keyInfoElement, signedInfo, signatureValue;\n            var info = new HashAlgorithmInfo(_signingContext.FileDigestAlgorithmName);\n\n            using (var canonicalHashAlgorithm = info.Create())\n            {\n                byte[] objectElementHash;\n                string canonicalizationMethodObjectId;\n\n                using (var objectElementCanonicalData = CanonicalizeElement(_objectElement, out canonicalizationMethodObjectId))\n                {\n                    objectElementHash = canonicalHashAlgorithm.ComputeHash(objectElementCanonicalData);\n                }\n\n                keyInfoElement = BuildKeyInfoElement();\n                Stream signerInfoCanonicalStream;\n                (signerInfoCanonicalStream, signedInfo) =\n                    BuildSignedInfoElement(\n                        (_objectElement, objectElementHash, info.XmlDSigIdentifier.AbsoluteUri, canonicalizationMethodObjectId)\n                    );\n                byte[] signerInfoElementHash;\n\n                using (signerInfoCanonicalStream)\n                {\n                    signerInfoElementHash = canonicalHashAlgorithm.ComputeHash(signerInfoCanonicalStream);\n                }\n\n                signatureValue = BuildSignatureValue(signerInfoElementHash);\n            }\n\n            _signatureElement.AppendChild(signedInfo);\n            _signatureElement.AppendChild(signatureValue);\n            _signatureElement.AppendChild(keyInfoElement);\n            _signatureElement.AppendChild(_objectElement);\n            _document.AppendChild(_signatureElement);\n\n            return _document;\n        }\n\n        private XmlElement BuildSignatureValue(byte[] signerInfoElementHash)\n        {\n            var signatureValueElement = CreateDSigElement(\"SignatureValue\");\n            signatureValueElement.InnerText = Convert.ToBase64String(_signingContext.SignDigest(signerInfoElementHash));\n\n            return signatureValueElement;\n        }\n\n        private Stream CanonicalizeElement(XmlElement element, out string canonicalizationMethodUri, Action<string>? setCanonicalization = null)\n        {\n            //The canonicalization transformer can't reasonable do just an element. It\n            //seems content to do an entire XmlDocument.\n\n            var transformer = new XmlDsigC14NTransform(false);\n            string? algorithm = transformer.Algorithm;\n\n            if (!string.IsNullOrEmpty(algorithm))\n            {\n                setCanonicalization?.Invoke(algorithm);\n\n                var newDocument = new XmlDocument(_document.NameTable);\n                newDocument.LoadXml(element.OuterXml);\n\n                transformer.LoadInput(newDocument);\n\n                var result = transformer.GetOutput(typeof(Stream));\n                canonicalizationMethodUri = algorithm;\n                if (result is Stream s)\n                {\n                    return s;\n                }\n            }\n\n            throw new NotSupportedException(\"Unable to canonicalize element.\");\n        }\n\n        private (Stream, XmlElement) BuildSignedInfoElement(params (XmlElement element, byte[] canonicalDigest, string digestAlgorithm, string canonicalizationMethod)[] objects)\n        {\n            var signingIdentifier = _signingContext.XmlDSigIdentifier;\n\n            var signedInfoElement = CreateDSigElement(\"SignedInfo\");\n            var canonicalizationMethodElement = CreateDSigElement(\"CanonicalizationMethod\");\n            var canonicalizationMethodAlgorithmAttribute = _document.CreateAttribute(\"Algorithm\");\n            canonicalizationMethodElement.Attributes.Append(canonicalizationMethodAlgorithmAttribute);\n\n            var signatureMethodElement = CreateDSigElement(\"SignatureMethod\");\n            var signatureMethodAlgorithmAttribute = _document.CreateAttribute(\"Algorithm\");\n            signatureMethodAlgorithmAttribute.Value = signingIdentifier.AbsoluteUri;\n            signatureMethodElement.Attributes.Append(signatureMethodAlgorithmAttribute);\n\n            signedInfoElement.AppendChild(canonicalizationMethodElement);\n            signedInfoElement.AppendChild(signatureMethodElement);\n\n            foreach (var (element, digest, digestAlgorithm, method) in objects)\n            {\n                var idFromElement = element.GetAttribute(\"Id\");\n                var reference = \"#\" + idFromElement;\n\n                var referenceElement = CreateDSigElement(\"Reference\");\n                var referenceUriAttribute = _document.CreateAttribute(\"URI\");\n                var referenceTypeAttribute = _document.CreateAttribute(\"Type\");\n                referenceUriAttribute.Value = reference;\n                referenceTypeAttribute.Value = OpcKnownUris.XmlDSigObject.AbsoluteUri;\n\n                referenceElement.Attributes.Append(referenceUriAttribute);\n                referenceElement.Attributes.Append(referenceTypeAttribute);\n\n                var referencesTransformsElement = CreateDSigElement(\"Transforms\");\n                var transformElement = CreateDSigElement(\"Transform\");\n                var transformAlgorithmAttribute = _document.CreateAttribute(\"Algorithm\");\n                transformAlgorithmAttribute.Value = method;\n                transformElement.Attributes.Append(transformAlgorithmAttribute);\n                referencesTransformsElement.AppendChild(transformElement);\n                referenceElement.AppendChild(referencesTransformsElement);\n\n                var digestMethodElement = CreateDSigElement(\"DigestMethod\");\n                var digestMethodAlgorithmAttribute = _document.CreateAttribute(\"Algorithm\");\n                digestMethodAlgorithmAttribute.Value = digestAlgorithm;\n                digestMethodElement.Attributes.Append(digestMethodAlgorithmAttribute);\n                referenceElement.AppendChild(digestMethodElement);\n\n                var digestValueElement = CreateDSigElement(\"DigestValue\");\n                digestValueElement.InnerText = Convert.ToBase64String(digest);\n                referenceElement.AppendChild(digestValueElement);\n\n                signedInfoElement.AppendChild(referenceElement);\n            }\n\n            var canonicalSignerInfo = CanonicalizeElement(signedInfoElement, out _, c => canonicalizationMethodAlgorithmAttribute.Value = c);\n\n            return (canonicalSignerInfo, signedInfoElement);\n        }\n\n        private XmlElement BuildKeyInfoElement()\n        {\n            var publicCertificate = Convert.ToBase64String(_signingContext.Certificate.Export(X509ContentType.Cert));\n            var keyInfoElement = CreateDSigElement(\"KeyInfo\");\n            var x509DataElement = CreateDSigElement(\"X509Data\");\n            var x509CertificateElement = CreateDSigElement(\"X509Certificate\");\n            x509CertificateElement.InnerText = publicCertificate;\n            x509DataElement.AppendChild(x509CertificateElement);\n            keyInfoElement.AppendChild(x509DataElement);\n\n            return keyInfoElement;\n        }\n\n        public void SetFileManifest(OpcSignatureManifest manifest)\n        {\n            var objectElement = CreateDSigElement(\"Object\");\n            var objectElementId = _document.CreateAttribute(\"Id\");\n            objectElementId.Value = \"idPackageObject\";\n            objectElement.Attributes.Append(objectElementId);\n\n            var manifestElement = CreateDSigElement(\"Manifest\");\n\n            foreach (var file in manifest.Manifest)\n            {\n                var referenceElement = CreateDSigElement(\"Reference\");\n                var referenceElementUriAttribute = _document.CreateAttribute(\"URI\");\n                referenceElementUriAttribute.Value = file.ReferenceUri.ToQualifiedPath();\n                referenceElement.Attributes.Append(referenceElementUriAttribute);\n\n                var digestMethod = CreateDSigElement(\"DigestMethod\");\n                var digestMethodAlgorithmAttribute = _document.CreateAttribute(\"Algorithm\");\n                digestMethodAlgorithmAttribute.Value = file.DigestAlgorithmIdentifier.AbsoluteUri;\n                digestMethod.Attributes.Append(digestMethodAlgorithmAttribute);\n                referenceElement.AppendChild(digestMethod);\n\n                var digestValue = CreateDSigElement(\"DigestValue\");\n                digestValue.InnerText = System.Convert.ToBase64String(file.Digest);\n                referenceElement.AppendChild(digestValue);\n\n\n                manifestElement.AppendChild(referenceElement);\n                objectElement.AppendChild(manifestElement);\n            }\n\n            var signaturePropertiesElement = CreateDSigElement(\"SignatureProperties\");\n            var signaturePropertyElement = CreateDSigElement(\"SignatureProperty\");\n            var signaturePropertyIdAttribute = _document.CreateAttribute(\"Id\");\n            var signaturePropertyTargetAttribute = _document.CreateAttribute(\"Target\");\n            signaturePropertyIdAttribute.Value = \"idSignatureTime\";\n            signaturePropertyTargetAttribute.Value = \"\";\n\n            signaturePropertyElement.Attributes.Append(signaturePropertyIdAttribute);\n            signaturePropertyElement.Attributes.Append(signaturePropertyTargetAttribute);\n\n            var signatureTimeElement = _document.CreateElement(\"SignatureTime\", OpcKnownUris.XmlDigitalSignature.AbsoluteUri);\n            var signatureTimeFormatElement = _document.CreateElement(\"Format\", OpcKnownUris.XmlDigitalSignature.AbsoluteUri);\n            var signatureTimeValueElement = _document.CreateElement(\"Value\", OpcKnownUris.XmlDigitalSignature.AbsoluteUri);\n            signatureTimeFormatElement.InnerText = \"YYYY-MM-DDThh:mm:ss.sTZD\";\n            signatureTimeValueElement.InnerText = _signingContext.ContextCreationTime.ToString(\"yyyy-MM-ddTHH:mm:ss.fzzz\", CultureInfo.InvariantCulture);\n\n            signatureTimeElement.AppendChild(signatureTimeFormatElement);\n            signatureTimeElement.AppendChild(signatureTimeValueElement);\n\n            signaturePropertyElement.AppendChild(signatureTimeElement);\n            signaturePropertiesElement.AppendChild(signaturePropertyElement);\n            objectElement.AppendChild(signaturePropertiesElement);\n\n            _objectElement = objectElement;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.Core/Tools/VsixSignTool.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Sign.Core.Timestamp;\n\nnamespace Sign.Core\n{\n    internal sealed class VsixSignTool : Tool, IVsixSignTool\n    {\n        // Dependency injection requires a public constructor.\n        public VsixSignTool(ILogger<IVsixSignTool> logger)\n            : base(logger)\n        {\n        }\n\n        public async Task<bool> SignAsync(FileInfo file, SignConfigurationSet configuration, SignOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n            ArgumentNullException.ThrowIfNull(options, nameof(options));\n\n            var failed = false;\n\n            // Append a signature\n            using (OpcPackage package = OpcPackage.Open(file.FullName, OpcPackageFileMode.ReadWrite))\n            {\n                Logger.LogInformation(Resources.SigningFile, file.FullName);\n\n                OpcPackageSignatureBuilder signBuilder = package.CreateSignatureBuilder();\n                signBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n\n                OpcSignature signature = signBuilder.Sign(configuration);\n\n                if (options.TimestampService is not null)\n                {\n                    OpcPackageTimestampBuilder timestampBuilder = signature.CreateTimestampBuilder();\n                    TimestampResult result = await timestampBuilder.SignAsync(options.TimestampService, options.TimestampHashAlgorithm);\n\n                    if (result == TimestampResult.Failed)\n                    {\n                        failed = true;\n                        Logger.LogError(Resources.ErrorSigningVsix);\n                    }\n                }\n            }\n\n            return !failed;\n        }\n    }\n}"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">Argument nemůže být prázdný.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Podepisování úlohy SignTool s tímto počtem souborů: {count}.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Platnost certifikátu vypršela.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Certifikát ještě není platný.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">Soubor {fileName} vrátil chybu {error}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">Soubor {fileName} vrátil výstup {output}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Podepisování úlohy Mage pomocí {count} souborů.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Vytváří se adresář {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Adresář {path} se odstranil.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Odstraňuje se adresář {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">Adresář {path} stále existuje.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Upravuje se úloha AppInstaller s tímto počtem souborů: {count}.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Při podepisování VSIX došlo k neurčené chybě.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Při pokusu o odstranění adresáře {path} došlo k výjimce.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Poskytlo se několik kontejnerů privátních klíčů. Pro úložiště uživatele použijte /k a pro úložiště počítače použijte /km.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Při použití /csp chybí kontejner privátního klíče. K poskytnutí kontejneru klíčů použijte /k nebo /km.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Extrahuje se kontejner {ContainerFilePath} do adresáře {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">Vypršel časový limit cesty k {0} a nelze ji ukončit.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">Odpověď {fileName} trvala příliš dlouho. Ukončovací kód procesu je {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">Odpověď souboru {0} trvala příliš dlouho,. Ukončovací kód procesu je {1}. Argumenty: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Spouští se {fileName} s parametry: {args}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Kontejner {ContainerFilePath} se znovu sestavuje z adresáře {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">Byla volána metoda SignAsync pro soubor {filePath}. Používá se {localFilePath} místně.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Probíhá pokus #{attempt} z {maxAttempts} pokusů po {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Nelze podepsat {0}{0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Nepovedlo se podepsat. Počet pokusů byl překročen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Podepisování selhalo s chybou {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Podepisování souboru {filePath}</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Podepisování souboru {filePath} proběhlo úspěšně.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Dokončeno za {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Odesílá se soubor {filePath} pro podepisování.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Zadaný režim {0} je neplatný.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Neznámý podpisový algoritmus.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">Vybraný algoritmus se nepodporuje.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Podepisování úlohy VsixSignTool pomocí tohoto počtu souborů: {count}.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">Das Argument darf nicht leer sein.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Der SignTool-Auftrag wird mit {count} Dateien signiert.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Das Zertifikat ist abgelaufen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Das Zertifikat ist noch nicht gültig.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} hat den Fehler {error} zurückgegeben</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} hat die Ausgabe {output} zurückgegeben</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Der Mage-Auftrag wird mit {count} Dateien signiert.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Das Verzeichnis {path} wird erstellt.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Das Verzeichnis {path} wurde gelöscht.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Das Verzeichnis {path} wird gelöscht.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">Das Verzeichnis {path} ist noch vorhanden.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">AppInstaller-Auftrag wird mit {count} Dateien bearbeitet.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Während der VSIX-Signierung ist ein nicht spezifizierter Fehler aufgetreten.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Beim Versuch, das Verzeichnis {path} zu löschen, ist eine Ausnahme aufgetreten.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Es wurden mehrere Container mit privatem Schlüssel bereitgestellt. Verwenden Sie entweder \"/k\" für Benutzerspeicher oder \"/km\" für Computerspeicher.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Der Container für den privaten Schlüssel fehlt bei Verwendung von \"/csp\". Verwenden Sie \"/k\" oder \"/km\", um einen Schlüsselcontainer bereitzustellen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Der Container {ContainerFilePath} wird in {DirectoryPath} extrahiert.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} hat ein Timeout und konnte nicht abgebrochen werden.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} hat zu lange gebraucht, um zu antworten. Der Prozessexitcode ist {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} hat zu lange gebraucht, um zu antworten. Der Prozessexitcode ist {1}. Argumente: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">{fileName} wird ausgeführt mit Parametern: '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Der Container {ContainerFilePath} wird aus {DirectoryPath} neu erstellt.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">SignAsync wurde für {filePath} aufgerufen. {localFilePath} wird lokal verwendet.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Der Versuch #{attempt} von {maxAttempts} Versuchen wird nach {seconds} Sek. ausgeführt.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">{0} konnte nicht signiert werden.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Fehler beim Signieren. Versuche wurden überschritten.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Das Signieren ist mit Fehler {errorCode} fehlgeschlagen.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">{filePath} wird signiert.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Signieren von {filePath} erfolgreich.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">In {millseconds} ms abgeschlossen.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">{filePath} wird zum Signieren übermittelt.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Der angegebene {0} ist ungültig.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Unbekannter Signaturalgorithmus.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">Der ausgewählte Algorithmus wird nicht unterstützt.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">VsixSignTool-Auftrag wird mit {count} Dateien signiert.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">El argumento no puede estar vacío.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Firmando el trabajo de SignTool con {count} archivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">El certificado ha expirado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">El certificado aún no es válido en tiempo.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} devolvió el error {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} devolvió la salida {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Firmando el trabajo de Mage con {count} archivos.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Creando directorio {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Directorio {path} eliminado.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Eliminando el directorio {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">El directorio {path} todavía existe.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Editando el trabajo AppInstaller con {count} archivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Error no especificado durante la firma VSIX.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Se produjo una excepción al intentar eliminar el directorio {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Se proporcionaron varios contenedores de clave privada. Use /k para almacenes de usuarios o /km para almacenes de máquinas.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Falta el contenedor de clave privada al usar /csp. Use /k o /km para proporcionar un contenedor de claves.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Extrayendo el contenedor {ContainerFilePath} en {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} agotó el tiempo de espera y no se pudo terminar.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} tardó demasiado en responder. El código de salida del proceso es {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} tardó demasiado en responder. El código de salida del proceso es {1}. Argumentos: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Ejecutando {fileName} con parámetros: '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Recompilando el contenedor {ContainerFilePath} desde {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">Se llamó a SignAsync para {filePath}. Usando {localFilePath} localmente.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Realizando el intento #{attempt} de {maxAttempts} intentos después de {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">No se pudo firmar {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">No se pudo firmar. Intentos superados.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Error al firmar: {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Firmando {filePath}.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Se firmó {filePath} correctamente.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Completado en {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Enviando {filePath} para la firma.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">El modo {0} especificado no es válido.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Algoritmo de firma desconocido.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">No se admite el algoritmo seleccionado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Firmando el trabajo de VsixSignTool con {count} archivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">L'argument ne peut pas être vide.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Signature du travail SignTool avec {count} fichiers.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Le certificat est arrivé à expiration.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">La date de début du certificat n’est pas encore valide.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} a renvoyé l'erreur {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} a renvoyé la sortie {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Signature du travail Mage avec {count} fichiers.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Création du répertoire {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Répertoire {path} supprimé.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Suppression du répertoire {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">Le répertoire {path} existe toujours.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Modification du travail AppInstaller avec {count} fichiers.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Une erreur non spécifiée s’est produite lors de la signature VSIX.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Une exception s’est produite lors de la tentative de suppression du répertoire {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Plusieurs conteneurs de clé privée ont été fournis. Utilisez /k pour les magasins d’utilisateurs ou /km pour les magasins d’ordinateurs.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Le conteneur de clé privée est manquant lors de l’utilisation de /csp. Utilisez /k ou /km pour fournir un conteneur de clé.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Extraction du conteneur {ContainerFilePath} vers {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} a expiré et n’a pas pu être arrêté.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} a mis trop de temps à répondre. Le code de sortie du processus est {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} a mis trop de temps à répondre. Le code de sortie du processus est {1}. Arguments : {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Exécution de {fileName} avec les paramètres : '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Reconstruction du conteneur {ContainerFilePath} à partir de {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">SignAsync appelé pour {filePath}. Utilisation locale de {localFilePath}.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Exécution de la tentative n° {attempt} sur {maxAttempts} après {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Impossible de signer {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Échec de la signature. Tentatives dépassées.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Échec de la signature avec l’erreur {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Signature de {filePath}.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">La signature de {filePath} a réussi.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Terminé en {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Envoi de {filePath} pour signature.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Le mode {0} spécifié n’est pas valide.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Algorithme de signature inconnu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">L’algorithme sélectionné n’est pas pris en charge.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Signature du travail VsixSignTool avec {count} fichiers.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">L'argomento non può essere vuoto.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Firma del processo SignTool con {count} file.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Il certificato è scaduto.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Il certificato non è ancora valido in termini di tempo.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} ha restituito l'errore {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} ha restituito l'output {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Firma del processo Mage con {count} file.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Creazione della directory {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">{path} directory eliminato.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Eliminazione della directory {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">{path} della directory esiste ancora.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Modifica del processo AppInstaller con {count} file.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Si è verificato un errore non specificato durante la firma di VSIX.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Si è verificata un'eccezione durante il tentativo di eliminare la directory {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Sono stati specificati più contenitori di chiavi private. Utilizzare /k per gli archivi utente o /km per gli archivi computer.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Contenitore di chiavi private mancante durante l'utilizzo di /csp. Usare /k o /km per specificare un contenitore di chiavi.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Estrazione del contenitore {ContainerFilePath} in {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">Si è verificato il timeout di {0} e non è stato possibile terminarlo.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} ha impiegato troppo tempo per rispondere. Il codice di uscita del processo è {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} ha impiegato troppo tempo per rispondere. Codice di uscita del processo {1}. Argomenti: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Esecuzione di {fileName} con parametri: '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Ricompilazione del contenitore {ContainerFilePath} da {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">SignAsync chiamato per {filePath}. Utilizzo di {localFilePath} in locale.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Esecuzione del tentativo #{attempt} di {maxAttempts} tentativi dopo {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Non è stato possibile accedere a {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Firma non riuscita. Tentativi superati.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Firma non riuscita con errore {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Firma di {filePath} in corso.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Firma di {filePath} completata.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Completato in {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Invio {filePath} per la firma.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">{0} specificato non valido.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Algoritmo di firma sconosciuto.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">L'algoritmo selezionato non è supportato.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Firma del processo VsixSignTool con {count} file.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">引数を空にすることはできません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">{count} 個のファイルを使用して SignTool ジョブに署名しています。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">証明書の有効期限が切れています。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">証明書はまだ有効な時間ではありません。</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} がエラー {error} を返しました</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} が出力 {output} を返しました</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">{count} 個のファイルを使用して Mage ジョブに署名しています。</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">ディレクトリ {path} を作成しています。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">ディレクトリ {path} が削除されました。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">ディレクトリ {path} を削除しています。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">ディレクトリ {path} がまだ存在します。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">{count} 個のファイルを使用して AppInstaller ジョブを編集しています。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">VSIX の署名中に未指定のエラーが発生しました。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">ディレクトリ {path} の削除しようとしている間に例外が発生しました。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">複数の秘密キー コンテナーが提供されています。ユーザー ストアの場合は /k、コンピューター ストアの場合は /km を使用します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp の使用中に秘密キー コンテナーが見つかりません。キー コンテナーを指定するには、/k または /km を使用します。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">コンテナー {ContainerFilePath} を {DirectoryPath} に抽出しています。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} がタイムアウトしましたが、強制終了できませんでした。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} の応答に時間がかかりすぎました。プロセス終了コードは {exitCode} です。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} の応答に時間がかかりすぎました。プロセス終了コードは {1} です。引数: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">パラメーター '{args}' を使用して {fileName} を実行しています。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">コンテナー {ContainerFilePath} を {DirectoryPath} から再構築しています。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">{filePath} に対して SignAsync が呼び出されました。{localFilePath} をローカルで使用しています。</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">{seconds} 秒後に {maxAttempts} 回の試行のうち #{attempt} 回目の試行を実行しています。</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">{0} に署名できませんでした。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">署名できませんでした。試行回数を超えました。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">署名がエラー {errorCode} で失敗しました。</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">{filePath} に署名しています。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">{filePath} の署名に成功しました。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">{millseconds} ミリ秒で完了しました</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">署名のために {filePath} を送信しています。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">指定された {0} は無効です。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">不明な署名アルゴリズムです。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">選択したアルゴリズムはサポートされていません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">{count} 個のファイルを使用して VsixSignTool ジョブに署名しています。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">인수는 비워 둘 수 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">{count} 파일로 SignTool 작업에 서명하는 중입니다.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">인증서가 만료되었습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">인증서가 아직 유효하지 않습니다.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName}에서 {error} 오류를 반환했습니다.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName}에서 출력 {output}을(를) 반환했습니다.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">{count} 파일로 Mage 작업에 서명하는 중입니다.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">디렉터리 {path}을(를) 생성하는 중입니다.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">디렉터리 {path}이(가) 삭제되었습니다.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">디렉터리 {path}을(를) 삭제하는 중입니다.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">디렉터리 {path}이(가) 여전히 존재합니다.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">{count} 파일로 AppInstaller 작업을 편집하는 중입니다.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">VSIX 서명 중에 지정되지 않은 오류가 발생했습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">디렉터리 {path}을(를) 삭제하려고 시도하는 동안 예외가 발생했습니다.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">여러 프라이빗 키 컨테이너가 제공되었습니다. 사용자 저장소에는 /k를, 컴퓨터 저장소에는 /km를 사용합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp를 사용하는 동안 프라이빗 키 컨테이너가 없습니다. /k 또는 /km를 사용하여 키 컨테이너를 제공합니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">컨테이너 {ContainerFilePath}을(를) {DirectoryPath}(으)로 추출하는 중입니다.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0}이(가) 시간 초과되어 종료할 수 없습니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName}이(가) 응답하는 데 너무 오래 걸렸습니다. 프로세스 종료 코드는 {exitCode}입니다.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} 응답하는 데 너무 오래 걸렸습니다. 프로세스 종료 코드는 {1}입니다. 인수: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">매개 변수 '{args}'을(를) 사용하여 {fileName}을(를) 실행 중입니다.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">{DirectoryPath}에서 컨테이너 {ContainerFilePath}을(를) 다시 빌드하는 중입니다.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">{filePath}에 대해 SignAsync가 호출되었습니다. 로컬에서 {localFilePath}을(를) 사용하고 있습니다.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">{seconds}초 후에 {maxAttempts}회 시도 중 #{attempt}을(를) 시도하는 중입니다.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">{0}에 서명할 수 없습니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">서명하지 못했습니다. 시도 횟수를 초과했습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">오류 {errorCode}(으)로 인해 서명에 실패했습니다.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">{filePath}에 서명하는 중입니다.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">{filePath} 서명에 성공했습니다.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">{millseconds} 밀리초 후에 완료되었습니다.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">서명을 위해 {filePath}을(를) 제출하는 중입니다.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">지정한 {0} 값이 잘못되었습니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">알 수 없는 서명 알고리즘입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">선택한 알고리즘은 지원되지 않습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">{count}개의 파일을 사용하여 VsixSignTool 작업에 서명합니다.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">Argument nie może być pusty.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Podpisywanie zadania SignTool przy użyciu {count} plików.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Certyfikat stracił ważność.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Certyfikat nie jest jeszcze ważny czasowo.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">Plik {fileName} zwrócił błąd {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">Plik {fileName} zwrócił dane wyjśćiowe {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Podpisywanie zadania Mage przy użyciu {count} plików.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Tworzenie ścieżki {path} katalogu.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Usunięto ścieżkę {path} katalogu.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Usuwanie ścieżki {path} katalogu.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">Ścieżka {path} katalogu nadal istnieje.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Edytowanie zadania AppInstaller przy użyciu {count} plików.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Wystąpił nieokreślony błąd podczas podpisywania jednostki VSIX.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Wystąpił wyjątek podczas próby usunięcia ścieżki {path} katalogu.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Podano wiele kontenerów kluczy prywatnych. Użyj opcji /k dla magazynów użytkowników lub opcji /km dla magazynów komputerów.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Brak kontenera kluczy prywatnych podczas używania opcji /csp. Użyj opcji /k lub /km, aby podać kontener kluczy.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Wyodrębnianie ścieżki {ContainerFilePath} kontenera do ścieżki {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">Przekroczono limit czasu dla ścieżki {0} i nie można jej zabić.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">W przypadku pliku {fileName} uzyskanie odpowiedzi trwało zbyt długo. Kod zakończenia procesu to {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">W przypadku pliku {0} uzyskanie odpowiedzi trwało zbyt długo. Kod zakończenia procesu to {1}. Argumenty: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Uruchamianie {fileName} za pomocą parametrów: '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Ponowne kompilowanie ścieżki {ContainerFilePath} kontenera ze ścieżki {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">Wywołano element SignAsync dla ścieżki {filePath}. Używanie ścieżki {localFilePath} lokalnie.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Wykonywanie #{attempt} próby z {maxAttempts} po {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Nie można podpisać ścieżki {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Nie można podpisać. Przekroczono liczbę prób.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Podpisywanie nie powiodło się z powodu błędu {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Podpisywanie ścieżki {filePath}.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Podpisywanie ścieżki {filePath} powiodło się.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Ukończono w {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Przesyłanie ścieżki {filePath} do podpisania.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Określony tryb {0} jest nieprawidłowy.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Nieznany algorytm podpisywania.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">Wybrany algorytm nie jest obsługiwany.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Podpisywanie zadania VsixSignTool przy użyciu {count} plików.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">O argumento não pode ser vazio.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Autenticando o trabalho SignTool com {count} arquivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">O certificado expirou.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">O certificado ainda não é válido.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} retornou o erro {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} retornou a saída {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Autenticando o trabalho Mage com {count} arquivos.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Criando o diretório {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Diretório {path} excluído.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Excluindo o diretório {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">O diretório {path} ainda existe.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Editando o trabalho do AppInstaller com {count} arquivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Ocorreu um erro não especificado durante a autenticação do VSIX.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Ocorreu uma exceção ao tentar excluir o diretório {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Vários contêineres de chave privada fornecidos. Use /k para repositórios de usuários ou /km para repositórios de computadores.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Contêiner de chave privada ausente ao usar /csp. Use /k ou /km para fornecer um contêiner de chave.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Extraindo o contêiner {ContainerFilePath} para {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} atingiu o tempo limite e não pôde ser eliminado.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} demorou muito para responder. O código de saída do processo é {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} demorou muito para responder. O código de saída do processo {1}. Argumentos: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Executando {fileName} com parâmetros: '{args}'.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Recriando o contêiner {ContainerFilePath} a partir do {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">SignAsync chamado para {filePath}. Usando {localFilePath} localmente.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Executando a tentativa #{attempt} de {maxAttempts} tentativas após {seconds} s.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Não foi possível autenticar {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Falha ao autenticar. Tentativas excedidas.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Falha na autenticação com o erro {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Autenticando {filePath}.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">A assinatura do {filePath} foi bem-sucedida.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Concluído em {millseconds} ms.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Enviando {filePath} para autenticação.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">O {0} especificado é inválido.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Algoritmo de assinatura desconhecido.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">O algoritmo selecionado não tem suporte.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Assinando o trabalho VsixSignTool com {count} arquivos.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">Аргумент не может быть пустым.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">Задание подписывания SignTool с несколькими файлами ({count}).</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Срок действия сертификата истек.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Срок действия сертификата еще не начался.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} возвращает ошибку {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} возвращает выходные данные {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Подписывание задания Mage с несколькими файлами ({count}).</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">Идет создание каталога {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">Каталог {path} удален.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">Идет удаление каталога {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">Каталог {path} все еще существует.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">Изменение задания AppInstaller с несколькими файлами ({count}).</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">Во время подписывания VSIX произошла неопознанная ошибка.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">Возникло исключение при попытке удаления каталога {path}.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Предоставлено несколько контейнеров закрытых ключей. Используйте /k для хранилищ пользователей или /km для хранилищ компьютеров.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">Отсутствует контейнер закрытого ключа при использовании /csp. Используйте /k или /km для предоставления контейнера ключей.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">Идет извлечение контейнера {ContainerFilePath} в {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">Время ожидания {0} истекло, и его не удалось завершить.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} слишком долго не отвечает. Код завершения процесса — {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} слишком долго не отвечает. Код завершения процесса {1}. Аргументы: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">Выполняется {fileName} с параметрами: \"{args}\".</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">Идет перестроение контейнера {ContainerFilePath} из {DirectoryPath}.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">SignAsync вызван для {filePath}. Используется {localFilePath} локально.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">Выполняется попытка #{attempt} из {maxAttempts} попыток за {seconds} с.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">Не удалось подписать {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">Не удалось подписать. Превышено количество попыток.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">Сбой подписывания с ошибкой {errorCode}.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">Подписывание {filePath}.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">Подписание {filePath} выполнено.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">Завершено за {millseconds} мс.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">Отправка {filePath} для подписывания.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Указанный параметр ({0}) недопустим.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Неизвестный алгоритм подписывания.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">Выбранный алгоритм не поддерживается.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">Подписывание задания VsixSignTool с несколькими файлами ({count}).</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">Bağımsız değişkeni boş olamaz.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">SignTool işi {count} dosya ile imzalanıyor.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">Sertifikanın süresi doldu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">Bu sertifikanın geçerlilik süresi henüz başlamadı.</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName}, {error} hatasını döndürdü</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName}, {output} çıkışını döndürdü</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">Mage işi {count} dosya ile imzalanıyor.</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">{path} dizini oluşturuluyor.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">{path} dizini silindi.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">{path} dizini siliniyor.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">{path} hala mevcut.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">AppInstaller işi {count} dosya ile düzenleniyor.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">VSIX imzalaması sırasında belirtilmeyen bir hata oluştu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">{path} dizini silinmeye çalışılırken bir özel durum oluştu.</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">Birden çok özel anahtar kapsayıcısı sağlandı. Kullanıcı depoları için /k veya makine depoları için /km kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">/csp kullanılırken özel anahtar kapsayıcısı eksik. Anahtar kapsayıcısı sağlamak için /k veya /km kullanın.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">{ContainerFilePath} kapsayıcısı {DirectoryPath} dizinine ayıklanıyor..</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} zaman aşımına uğradı ve sonlandırılamadı.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} dosyasının yanıt vermesi çok uzun sürdü. İşlem çıkış kodu: {exitCode}.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} dosyasının yanıt vermesi çok uzun sürdü. İşlem çıkış kodu: {1}. Bağımsız değişkenler: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">{fileName} dosyası '{args}' parametreleriyle çalıştırılıyor.</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">{ContainerFilePath} kapsayıcısı {DirectoryPath} dizininden yeniden derleniyor.</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">{filePath} SignAsync çağrıldı. Yerel olarak {localFilePath} kullanılıyor.</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">{seconds} sn sonra #{attempt}/{maxAttempts} deneme yapılıyor.</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">{0} imzalamadı.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">İmzalanamadı. Deneme sayısı aşıldı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">İmzalama {errorCode} hatasıyla başarısız oldu.</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">{filePath} imzalanıyor.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">{filePath} imzalama işlemi başarılı oldu.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">{millseconds} ms içinde tamamlandı.</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">{filePath} imzalama için gönderiliyor.</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">Belirtilen {0} geçersiz.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">Bilinmeyen imzalama algoritması.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">Seçilen algoritma desteklenmiyor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">VsixSignTool işi {count} dosya ile imzalanıyor.</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">参数不能为空。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">正在对包含 {count} 个文件的 SignTool 作业进行签名。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">证书已过期。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">该证书尚未生效。</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} 返回错误 {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} 返回输出 {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">正在对包含 {count} 个文件的 Mage 作业进行签名。</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">正在创建目录 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">已删除目录 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">正在删除目录 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">目录 {path} 仍然存在。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">正在编辑包含 {count} 个文件的 AppInstaller 作业。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">VSIX 签名期间发生未指定的错误。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">尝试删除目录 {path} 时发生异常。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">提供了多个私钥容器。对用户存储使用 /k，或者对计算机存储使用 /km。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">使用 /csp 时缺少私钥容器。使用 /k 或 /km 提供密钥容器。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">正在将容器 {ContainerFilePath} 提取到 {DirectoryPath}。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} 超时，无法终止。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} 响应时间太长。进程退出代码为 {exitCode}。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} 响应的时间太长。进程退出代码为 {1}。参数: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">正在使用参数“{args}”运行 {fileName}。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">正在从 {DirectoryPath} 重新生成容器 {ContainerFilePath}。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">为 {filePath} 调用了 SignAsync。请在本地使用 {localFilePath}。</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">正在 {seconds} 秒后执行第 #{attempt} 次尝试(最多 {maxAttempts} 次)。</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">无法对 {0} 进行签名。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">签名失败。超过了尝试次数。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">签名失败，出现错误 {errorCode}。</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">正在对 {filePath} 进行签名。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">已成功对 {filePath} 签名。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">已完成时间(以 {millseconds} 毫秒为单位)。</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">正在提交 {filePath} 进行签名。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">指定的 {0} 无效。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">未知签名算法。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">不支持所选算法。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">正在对包含 {count} 个文件的 VsixSignTool 作业进行签名。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.Core/xlf/Resources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"ArgumentCannotBeEmpty\">\n        <source>The argument cannot be empty.</source>\n        <target state=\"translated\">引數不可為空白。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"AzureSignToolSignatureProviderSigning\">\n        <source>Signing SignTool job with {count} files.</source>\n        <target state=\"translated\">正在簽署具有 {count} 個檔案的 SignTool 工作。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateIsExpired\">\n        <source>The certificate is expired.</source>\n        <target state=\"translated\">憑證已過期。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateIsNotYetTimeValid\">\n        <source>The certificate is not yet time valid.</source>\n        <target state=\"translated\">憑證尚未生效。</target>\n        <note>A certificate has a validity period with start and end dates.  \"not yet time valid\" means that the start date is in the future.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardError\">\n        <source>{fileName} returned the error {error}</source>\n        <target state=\"translated\">{fileName} 已傳回錯誤 {error}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{error}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"CliStandardOutput\">\n        <source>{fileName} returned the output {output}</source>\n        <target state=\"translated\">{fileName} 已傳回輸出 {output}</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{output}\"} is verbose output from a tool.</note>\n      </trans-unit>\n      <trans-unit id=\"ClickOnceSignatureProviderSigning\">\n        <source>Signing Mage job with {count} files.</source>\n        <target state=\"translated\">正在簽署具有 {count} 個檔案的 Mage 工作。</target>\n        <note>{Locked=\"Mage\"} is another signing tool.  {Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"CreatingDirectory\">\n        <source>Creating directory {path}.</source>\n        <target state=\"translated\">正在建立目錄 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletedDirectory\">\n        <source>Directory {path} deleted.</source>\n        <target state=\"translated\">已刪除目錄 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DeletingDirectory\">\n        <source>Deleting directory {path}.</source>\n        <target state=\"translated\">正在刪除目錄 {path}。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"DirectoryNotDeleted\">\n        <source>Directory {path} still exists.</source>\n        <target state=\"translated\">目錄 {path} 仍然存在。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"EditingAppInstaller\">\n        <source>Editing AppInstaller job with {count} files.</source>\n        <target state=\"translated\">正在編輯具有 {count} 個檔案的 AppInstaller 工作。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n      <trans-unit id=\"ErrorSigningVsix\">\n        <source>An unspecified error occurred during VSIX signing.</source>\n        <target state=\"translated\">VSIX 簽署期間發生未指定的錯誤。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"ExceptionWhileDeletingDirectory\">\n        <source>An exception occurred while attempting to delete directory {path}.</source>\n        <target state=\"translated\">嘗試刪除目錄 {path} 時發生例外狀況。</target>\n        <note>{Placeholder=\"{path}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"MultiplePrivateKeyContainersError\">\n        <source>Multiple private key containers provided. Use either /k for user stores or /km for machine stores.</source>\n        <target state=\"translated\">已提供多個私密金鑰。使用者存放區使用 /k，機器存放區則使用 /km。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"NoPrivateKeyContainerError\">\n        <source>Private key container missing while using /csp. Use /k or /km to provide a key container.</source>\n        <target state=\"translated\">使用 /csp 時遺漏私密金鑰容器。使用 /k 或 /km 來提供金鑰容器。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"OpeningContainer\">\n        <source>Extracting container {ContainerFilePath} to {DirectoryPath}.</source>\n        <target state=\"translated\">正在將容器 {ContainerFilePath} 解壓縮到 {DirectoryPath}。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessCouldNotBeKilled\">\n        <source>{0} timed out and could not be killed.</source>\n        <target state=\"translated\">{0} 逾時，無法終止。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTime\">\n        <source>{fileName} took too long to respond. The process exit code is {exitCode}.</source>\n        <target state=\"translated\">{fileName} 的回應時間太長。處理序結束代碼為 {exitCode}。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{exitCode}\"} is a number representing the error code returned from a process.</note>\n      </trans-unit>\n      <trans-unit id=\"ProcessDidNotExitInTimeWithArguments\">\n        <source>{0} took too long to respond. The process exit code is {1}. Arguments: {2}</source>\n        <target state=\"translated\">{0} 的回應時間太長。處理序結束代碼為 {1}。引數: {2}</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file name.  {NumberedPlaceholder=\"{1}\"} is a process exit code.  {NumberedPlaceholder=\"{2}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"RunningCli\">\n        <source>Running {fileName} with parameters: '{args}'.</source>\n        <target state=\"translated\">正在執行具有參數 '{args}' 的 {fileName}。</target>\n        <note>{Placeholder=\"{fileName}\"} is a file name, and {Placeholder=\"{args}\"} is process arguments.</note>\n      </trans-unit>\n      <trans-unit id=\"SavingContainer\">\n        <source>Rebuilding container {ContainerFilePath} from {DirectoryPath}.</source>\n        <target state=\"translated\">正在從 {DirectoryPath} 重建容器 {ContainerFilePath}。</target>\n        <note>{Placeholder=\"{ContainerFilePath}\"} is a file path, and {Placeholder=\"{DirectoryPath}\"} is a directory path.</note>\n      </trans-unit>\n      <trans-unit id=\"SignAsyncCalled\">\n        <source>SignAsync called for {filePath}. Using {localFilePath} locally.</source>\n        <target state=\"translated\">已針對 {filePath} 呼叫 SignAsync。正在本機使用 {localFilePath}。</target>\n        <note>{Placeholder=\"{filePath}\", \"{localFilePath}\"} are both file paths.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningAttempt\">\n        <source>Performing attempt #{attempt} of {maxAttempts} attempts after {seconds} s.</source>\n        <target state=\"translated\">在 {seconds} 秒後執行 {maxAttempts} 次嘗試的第 attempt #{attempt} 次嘗試。</target>\n        <note>{Placeholder=\"{attempt}\", \"{maxAttempts}\"} are numbers representing the current attempt (as a number) and the maximum allowed attempts (as a number).  {Placeholder=\"{seconds}\"} is a decimal number representing the number of seconds elapsed, and \"s\" is the unit abbreviation for seconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailed\">\n        <source>Could not sign {0}.</source>\n        <target state=\"translated\">無法簽署 {0}。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFailedAfterAllAttempts\">\n        <source>Failed to sign. Attempts exceeded.</source>\n        <target state=\"translated\">無法簽署。超過嘗試次數。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"SigningFailedWithError\">\n        <source>Signing failed with error {errorCode}.</source>\n        <target state=\"translated\">簽署失敗。錯誤 {errorCode}。</target>\n        <note>{Placeholder=\"{errorCode}\"} is an error code.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningFile\">\n        <source>Signing {filePath}.</source>\n        <target state=\"translated\">正在簽署 {filePath}。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceeded\">\n        <source>Signing {filePath} succeeded.</source>\n        <target state=\"translated\">簽署 {filePath} 成功。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"SigningSucceededWithTimeElapsed\">\n        <source>Completed in {millseconds} ms.</source>\n        <target state=\"translated\">已在 {millseconds} 毫秒內完成。</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"SubmittingFileForSigning\">\n        <source>Submitting {filePath} for signing.</source>\n        <target state=\"translated\">正在提交 {filePath} 進行簽署。</target>\n        <note>{Placeholder=\"{filePath}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolOpcContentTypeInvalid\">\n        <source>Specified {0} is invalid.</source>\n        <target state=\"translated\">指定的 {0} 無效。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is the mode for reading OPC content. Either \"default\" or \"override\".</note>\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnknownSigningAlgorithm\">\n        <source>Unknown signing algorithm.</source>\n        <target state=\"translated\">未知的簽署演算法。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VSIXSignToolUnsupportedAlgorithm\">\n        <source>The algorithm selected is not supported.</source>\n        <target state=\"translated\">不支持選取的演算法。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"VsixSignatureProviderSigning\">\n        <source>Signing VsixSignTool job with {count} files.</source>\n        <target state=\"translated\">正在簽署具有 {count} 個檔案的 OpenVsixSignTool 工作。</target>\n        <note>{Placeholder=\"{count}\"} is the number of files to be signed.</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/ArtifactSigningService.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Azure;\nusing Azure.CodeSigning;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.ArtifactSigning\n{\n    internal sealed class ArtifactSigningService : ISignatureAlgorithmProvider, ICertificateProvider, IDisposable\n    {\n        private readonly CertificateProfileClient _client;\n        private readonly string _accountName;\n        private readonly string _certificateProfileName;\n        private readonly ILogger<ArtifactSigningService> _logger;\n        private readonly SemaphoreSlim _mutex = new(1);\n        private X509Certificate2? _certificate;\n\n        public ArtifactSigningService(\n            CertificateProfileClient certificateProfileClient,\n            string accountName,\n            string certificateProfileName,\n            ILogger<ArtifactSigningService> logger)\n        {\n            ArgumentNullException.ThrowIfNull(certificateProfileClient, paramName: nameof(certificateProfileClient));\n            ArgumentException.ThrowIfNullOrEmpty(accountName, nameof(accountName));\n            ArgumentException.ThrowIfNullOrEmpty(certificateProfileName, nameof(certificateProfileName));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _client = certificateProfileClient;\n            _accountName = accountName;\n            _certificateProfileName = certificateProfileName;\n            _logger = logger;\n        }\n\n        public void Dispose()\n        {\n            _mutex.Dispose();\n            _certificate?.Dispose();\n            GC.SuppressFinalize(this);\n        }\n\n        public async Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken)\n        {\n            if (_certificate is not null)\n            {\n                return new X509Certificate2(_certificate);\n            }\n\n            await _mutex.WaitAsync(cancellationToken);\n\n            try\n            {\n                if (_certificate is null)\n                {\n                    Stopwatch stopwatch = Stopwatch.StartNew();\n\n                    _logger.LogTrace(Resources.FetchingCertificate);\n\n                    Response<Stream> response = await _client.GetSignCertificateChainAsync(_accountName, _certificateProfileName, cancellationToken: cancellationToken);\n\n                    using (response.Value)\n                    {\n                        byte[] rawData = new byte[response.Value.Length];\n                        response.Value.Read(rawData, 0, rawData.Length);\n\n                        X509Certificate2Collection collection = [];\n                        collection.Import(rawData);\n\n                        // This should contain the certificate chain in root->leaf order.\n                        _certificate = collection[collection.Count - 1];\n\n                        _logger.LogTrace(Resources.FetchedCertificate, stopwatch.Elapsed.TotalMilliseconds);\n                        //print the certificate info\n                        _logger.LogTrace($\"{Resources.CertificateDetails}{Environment.NewLine}{_certificate.ToString(verbose: true)}\");\n                    }\n                }\n            }\n            finally\n            {\n                _mutex.Release();\n            }\n\n            return new X509Certificate2(_certificate);\n        }\n\n        public async Task<RSA> GetRsaAsync(CancellationToken cancellationToken)\n        {\n            using X509Certificate2 certificate = await GetCertificateAsync(cancellationToken);\n            RSA rsaPublicKey = certificate.GetRSAPublicKey()!;\n            return new RSAArtifactSigning(_client, _accountName, _certificateProfileName, rsaPublicKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/ArtifactSigningServiceProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.ArtifactSigning\n{\n    internal sealed class ArtifactSigningServiceProvider : ISignatureProvider\n    {\n        public ISignatureAlgorithmProvider GetSignatureAlgorithmProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return serviceProvider.GetRequiredService<ArtifactSigningService>();\n        }\n\n        public ICertificateProvider GetCertificateProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return serviceProvider.GetRequiredService<ArtifactSigningService>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/RSAArtifactSigning.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Azure;\nusing Azure.CodeSigning;\nusing Azure.CodeSigning.Models;\n\nnamespace Sign.SignatureProviders.ArtifactSigning\n{\n    internal sealed class RSAArtifactSigning : RSA\n    {\n        private readonly CertificateProfileClient _client;\n        private readonly string _accountName;\n        private readonly string _certificateProfileName;\n        private readonly RSA _rsaPublicKey;\n\n        public RSAArtifactSigning(\n            CertificateProfileClient client,\n            string accountName,\n            string certificateProfileName,\n            RSA rsaPublicKey)\n        {\n            ArgumentNullException.ThrowIfNull(client, nameof(client));\n            ArgumentException.ThrowIfNullOrEmpty(accountName, nameof(accountName));\n            ArgumentException.ThrowIfNullOrEmpty(certificateProfileName, nameof(certificateProfileName));\n            ArgumentNullException.ThrowIfNull(rsaPublicKey, nameof(rsaPublicKey));\n\n            _client = client;\n            _accountName = accountName;\n            _certificateProfileName = certificateProfileName;\n            _rsaPublicKey = rsaPublicKey;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                _rsaPublicKey.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n        public override RSAParameters ExportParameters(bool includePrivateParameters)\n        {\n            if (includePrivateParameters)\n            {\n                throw new NotSupportedException();\n            }\n\n            return _rsaPublicKey.ExportParameters(false);\n        }\n\n        public override void ImportParameters(RSAParameters parameters)\n            => throw new NotImplementedException();\n\n        public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)\n        {\n            SignatureAlgorithm signatureAlgorithm = GetSignatureAlgorithm(hash, padding);\n            SignRequest request = new(signatureAlgorithm, hash);\n            CertificateProfileSignOperation operation = _client.StartSign(_accountName, _certificateProfileName, request);\n            Response<SignStatus> response = operation.WaitForCompletion();\n            return response.Value.Signature;\n        }\n\n        public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)\n            => _rsaPublicKey.VerifyHash(hash, signature, hashAlgorithm, padding);\n\n        private static SignatureAlgorithm GetSignatureAlgorithm(byte[] digest, RSASignaturePadding padding)\n            => digest.Length switch\n            {\n                32 => padding == RSASignaturePadding.Pss ? Azure.CodeSigning.Models.SignatureAlgorithm.PS256 : Azure.CodeSigning.Models.SignatureAlgorithm.RS256,\n                48 => padding == RSASignaturePadding.Pss ? Azure.CodeSigning.Models.SignatureAlgorithm.PS384 : Azure.CodeSigning.Models.SignatureAlgorithm.RS384,\n                64 => padding == RSASignaturePadding.Pss ? Azure.CodeSigning.Models.SignatureAlgorithm.PS512 : Azure.CodeSigning.Models.SignatureAlgorithm.RS512,\n                _ => throw new NotSupportedException(),\n            };\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.SignatureProviders.ArtifactSigning {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.SignatureProviders.ArtifactSigning.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Certificate details:.\n        /// </summary>\n        internal static string CertificateDetails {\n            get {\n                return ResourceManager.GetString(\"CertificateDetails\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetched certificate. [{milliseconds} ms].\n        /// </summary>\n        internal static string FetchedCertificate {\n            get {\n                return ResourceManager.GetString(\"FetchedCertificate\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetching certificate from Artifact Signing certificate profile..\n        /// </summary>\n        internal static string FetchingCertificate {\n            get {\n                return ResourceManager.GetString(\"FetchingCertificate\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"CertificateDetails\" xml:space=\"preserve\">\n    <value>Certificate details:</value>\n  </data>\n  <data name=\"FetchedCertificate\" xml:space=\"preserve\">\n    <value>Fetched certificate. [{milliseconds} ms]</value>\n    <comment>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</comment>\n  </data>\n  <data name=\"FetchingCertificate\" xml:space=\"preserve\">\n    <value>Fetching certificate from Artifact Signing certificate profile.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/Sign.SignatureProviders.ArtifactSigning.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsShipping>true</IsShipping>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <!--\n    NuGet package Azure.CodeSigning.Sdk 0.1.96 depends on NuGet package Azure.Core 1.25.0 or later. However, Azure.CodeSigning.dll\n    (in the Azure.CodeSigning.Sdk package) actually references Azure.Core.dll 1.27.0. When this mismatch is resolved, this explicit\n    package reference can be removed here and in the Directory.Packages.props.\n    -->\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.CodeSigning.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Sign.Core\\Sign.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"sign\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.ArtifactSigning.Test\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Podrobnosti certifikátu:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Načetl se certifikát. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Načítá se certifikát z profilu certifikátu Artifact Signing.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Zertifikatdetails:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Zertifikat abgerufen. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Das Zertifikat wird aus dem Zertifikatprofil der Artefaktsignatur abgerufen.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Detalles del certificado:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado capturado. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Capturando el certificado del perfil de certificado de firma de artefactos.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Détails du certificat :</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificat récupéré. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Récupération du certificat à partir du profil de certificat de Signature d'artefact.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Dettagli certificato:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Il certificato è stato recuperato. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Recupero del certificato dal profilo del certificato di Firma artefatti.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">証明書の詳細:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">証明書をフェッチしました。[{milliseconds} ミリ秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Artifact Signing 証明書プロファイルから証明書をフェッチしています。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">인증서 세부 정보:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">인증서를 가져왔습니다. [{milliseconds}ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Artifact Signing 인증서 프로필에서 인증서를 가져오는 중입니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Szczegóły certyfikatu:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Pobrano certyfikat. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Pobieranie certyfikatu z profilu certyfikatów rozwiązania Artifact Signing.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Detalhes do certificado:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado buscado. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Buscar certificado do perfil de certificado de Assinatura de Artefatos.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Сведения о сертификате:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Получен сертификат. [{milliseconds} мс]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Выполняется получение сертификата из профиля сертификата подписания артефактов.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Sertifika ayrıntıları:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Sertifika getirildi. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">Yapıt İmzalama sertifikası profilinden sertifika getiriliyor.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">证书详细信息:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">已提取证书。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">正在从工件签名证书配置文件中提取证书。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.ArtifactSigning/xlf/Resources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">憑證詳細資料:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">已擷取憑證。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Artifact Signing certificate profile.</source>\n        <target state=\"translated\">正在從成品簽署憑證設定檔擷取憑證。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/CertificateStoreService.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Versioning;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.CertificateStore\n{\n    /// <summary>\n    /// Creates an object used to access Certificate Stores and acquire certificates and RSA keys (if applicable).\n    /// </summary>\n    internal sealed class CertificateStoreService : ISignatureAlgorithmProvider, ICertificateProvider\n    {\n        private readonly string _certificateFingerprint;\n        private readonly HashAlgorithmName _certificateFingerprintAlgorithm;\n        private readonly string? _cryptoServiceProvider;\n        private readonly string? _privateKeyContainer;\n        private readonly string? _certificatePath;\n        private readonly string? _certificatePassword;\n        private readonly bool _isPrivateMachineKeyContainer;\n        private readonly bool _isInteractive;\n\n        private readonly ILogger<CertificateStoreService> _logger;\n\n        internal CertificateStoreService(\n            IServiceProvider serviceProvider,\n            string certificateFingerprint,\n            HashAlgorithmName certificateFingerprintAlgorithm,\n            string? cryptoServiceProvider,\n            string? privateKeyContainer,\n            string? certificatePath,\n            string? certificatePassword,\n            bool isPrivateMachineKeyContainer,\n            bool isInteractive)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n            ArgumentException.ThrowIfNullOrEmpty(certificateFingerprint, nameof(certificateFingerprint));\n\n            _certificateFingerprint = certificateFingerprint;\n            _certificateFingerprintAlgorithm = certificateFingerprintAlgorithm;\n            _cryptoServiceProvider = cryptoServiceProvider;\n            _privateKeyContainer = privateKeyContainer;\n            _isPrivateMachineKeyContainer = isPrivateMachineKeyContainer;\n            _isInteractive = isInteractive;\n            _certificatePath = certificatePath;\n            _certificatePassword = certificatePassword;\n\n            _logger = serviceProvider.GetRequiredService<ILogger<CertificateStoreService>>();\n        }\n\n\n        /// <summary>\n        /// Acquires the RSA private key from either a CSP registered in the machine or from the certificate provided by the user.\n        /// </summary>\n        /// <param name=\"cancellationToken\">Cancellation token for this asynchronous task.</param>\n        /// <returns><see cref=\"RSA\"/> algorithm object used to acquire the private key.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when the provided key is not RSA.</exception>\n        [SupportedOSPlatform(\"windows\")] // CspParameters is Windows-only but project uses cross platform frameworks. Dotnet/Sign is Windows only\n        public async Task<RSA> GetRsaAsync(CancellationToken cancellationToken)\n        {\n            // Get RSA from a cryptographic service provider\n            if (!string.IsNullOrEmpty(_privateKeyContainer) && !string.IsNullOrEmpty(_cryptoServiceProvider))\n            {\n                var cngKeyFlags = _isInteractive ? CngKeyOpenOptions.None : CngKeyOpenOptions.Silent;\n\n                if (_isPrivateMachineKeyContainer)\n                {\n                    cngKeyFlags |= CngKeyOpenOptions.MachineKey;\n\n                    RSACryptoServiceProvider.UseMachineKeyStore = true;\n                }\n                else\n                {\n                    cngKeyFlags |= CngKeyOpenOptions.UserKey;\n                }\n\n                using CngKey cngKey = CngKey.Open(\n                    _privateKeyContainer,\n                    new CngProvider(_cryptoServiceProvider), cngKeyFlags);\n\n                return new RSACng(cngKey);\n            }\n\n            // Certificate wasn't in CSP. Attempt to extract from store or provided file.\n            const string RSA = \"1.2.840.113549.1.1.1\";\n\n            using X509Certificate2 certificate = await GetStoreCertificateAsync();\n            string keyAlgorithm = certificate.GetKeyAlgorithm();\n\n            switch (keyAlgorithm)\n            {\n                case RSA:\n                    return certificate.GetRSAPrivateKey() ?? throw new InvalidOperationException(Resources.CertificateRSANotFound);\n                default:\n                    throw new InvalidOperationException(Resources.UnsupportedPublicKeyAlgorithm);\n            }\n        }\n\n        /// <summary>\n        /// Gets a certificate from a local (user or machine) certificate store or from a provided certificate file.\n        /// </summary>\n        /// <returns>A <see cref=\"X509Certificate2\"/> certificate specified by a certificate Fingerprint.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the certificate fingerprint wasn't found in any store.</exception>\n        public async Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken)\n            => await GetStoreCertificateAsync();\n\n        private Task<X509Certificate2> GetStoreCertificateAsync()\n        {\n            Stopwatch stopwatch = Stopwatch.StartNew();\n\n            // Check the provided file if any.\n            if (!string.IsNullOrEmpty(_certificatePath))\n            {\n                _logger.LogTrace(Resources.FetchingCertificateFromFile);\n\n                X509Certificate2Collection certCollection = new();\n                certCollection.Import(_certificatePath, _certificatePassword, X509KeyStorageFlags.EphemeralKeySet);\n\n                foreach (var cert in certCollection)\n                {\n                    string actualFingerprint = cert.GetCertHashString(_certificateFingerprintAlgorithm);\n\n                    if (string.Equals(actualFingerprint, _certificateFingerprint, StringComparison.InvariantCultureIgnoreCase))\n                    {\n                        _logger.LogTrace(Resources.FetchedCertificateFromFile, stopwatch.Elapsed.TotalMilliseconds);\n\n                        return Task.FromResult(new X509Certificate2(cert));\n                    }\n                }\n\n                throw new ArgumentException(string.Format(Resources.CertificateNotFoundInFile, _certificateFingerprint, Path.GetFileName(_certificatePath)));\n            }\n\n            _logger.LogTrace(Resources.FetchingCertificateFromCertificateStore);\n\n            // Search User or Machine certificate stores.\n            if (!string.IsNullOrEmpty(_privateKeyContainer)\n                && _isPrivateMachineKeyContainer\n                    ? TryFindCertificate(StoreLocation.LocalMachine, _certificateFingerprint, out X509Certificate2? certificate)\n                    : TryFindCertificate(StoreLocation.CurrentUser, _certificateFingerprint, out certificate))\n            {\n                _logger.LogTrace(Resources.FetchedCertificateFromCertificateStore, stopwatch.Elapsed.TotalMilliseconds);\n\n                return Task.FromResult(certificate);\n            }\n\n            throw new ArgumentException(_isPrivateMachineKeyContainer ? Resources.CertificateNotFoundInMachineStore : Resources.CertificateNotFoundInUserStore, _certificateFingerprint);\n        }\n\n        private bool TryFindCertificate(StoreLocation storeLocation, string expectedFingerprint, [NotNullWhen(true)] out X509Certificate2? certificate)\n        {\n            // Check machine certificate store.\n            using (X509Store store = new(StoreName.My, storeLocation))\n            {\n                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);\n\n                foreach (var cert in store.Certificates)\n                {\n                    string actualFingerprint = cert.GetCertHashString(_certificateFingerprintAlgorithm);\n\n                    if (string.Equals(actualFingerprint, expectedFingerprint, StringComparison.InvariantCultureIgnoreCase))\n                    {\n                        certificate = cert;\n\n                        return true;\n                    }\n                }\n\n                certificate = null;\n\n                return false;\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/CertificateStoreServiceProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.CertificateStore\n{\n    /// <summary>\n    /// Provider that initializes a new <see cref=\"CertificateStoreService\"/> if required.\n    /// </summary>\n    internal class CertificateStoreServiceProvider : ISignatureProvider\n    {\n        private readonly string _certificateFingerprint;\n        private readonly HashAlgorithmName _certificateFingerprintAlgorithm;\n        private readonly string? _cryptoServiceProvider;\n        private readonly string? _privateKeyContainer;\n        private readonly string? _certificateFilePath;\n        private readonly string? _certificateFilePassword;\n        private readonly bool _isMachineKeyContainer;\n        private readonly bool _isInteractive;\n\n        private readonly object _lockObject = new();\n        private CertificateStoreService? _certificateStoreService;\n\n        /// <summary>\n        /// Creates a new service provider for accessing certificates within a store.\n        /// </summary>\n        /// <param name=\"certificateFingerprint\">Required fingerprint used to identify the certificate in the store.</param>\n        /// <param name=\"certificateFingerprintAlgorithm\">Fingerprint algorithm used to identify the algorithm type of the fingerprint.</param>\n        /// <param name=\"cryptoServiceProvider\">Optional Cryptographic service provider used to access 3rd party certificate stores.</param>\n        /// <param name=\"privateKeyContainer\">Optional Key Container stored in either the per-user or per-machine location.</param>\n        /// <param name=\"certificateFilePath\">Optional path to the PFX, P7B, or CER file with the certificate.</param>\n        /// <param name=\"certificateFilePassword\">Optional password used to open the provided certificate.</param>\n        /// <param name=\"isMachineKeyContainer\">Optional Flag used to denote per-machine key container should be used.</param>\n        /// <param name=\"isInteractive\">Optional Flag used to denote when user interactions are expected during key retrieval.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when a required argument is empty not valid.</exception>\n        internal CertificateStoreServiceProvider(\n            string certificateFingerprint,\n            HashAlgorithmName certificateFingerprintAlgorithm,\n            string? cryptoServiceProvider,\n            string? privateKeyContainer,\n            string? certificateFilePath,\n            string? certificateFilePassword,\n            bool isMachineKeyContainer,\n            bool isInteractive)\n        {\n            ArgumentException.ThrowIfNullOrEmpty(certificateFingerprint, nameof(certificateFingerprint));\n\n            // Both or neither can be provided when accessing a certificate.\n            if (!string.IsNullOrEmpty(cryptoServiceProvider) == string.IsNullOrEmpty(privateKeyContainer))\n            {\n                ArgumentException.ThrowIfNullOrEmpty(cryptoServiceProvider, nameof(cryptoServiceProvider));\n                ArgumentException.ThrowIfNullOrEmpty(privateKeyContainer, nameof(privateKeyContainer));\n            }\n\n            _certificateFingerprint = certificateFingerprint;\n            _certificateFingerprintAlgorithm = certificateFingerprintAlgorithm;\n            _cryptoServiceProvider = cryptoServiceProvider;\n            _privateKeyContainer = privateKeyContainer;\n            _isMachineKeyContainer = isMachineKeyContainer;\n            _isInteractive = isInteractive;\n            _certificateFilePath = certificateFilePath;\n            _certificateFilePassword = certificateFilePassword;\n        }\n\n        public ISignatureAlgorithmProvider GetSignatureAlgorithmProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return GetService(serviceProvider);\n        }\n\n        public ICertificateProvider GetCertificateProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return GetService(serviceProvider);\n        }\n\n        private CertificateStoreService GetService(IServiceProvider serviceProvider)\n        {\n            if (_certificateStoreService is not null)\n            {\n                return _certificateStoreService;\n            }\n\n            lock (_lockObject)\n            {\n                if (_certificateStoreService is not null)\n                {\n                    return _certificateStoreService;\n                }\n\n                _certificateStoreService = new CertificateStoreService(\n                    serviceProvider,\n                    _certificateFingerprint,\n                    _certificateFingerprintAlgorithm,\n                    _cryptoServiceProvider,\n                    _privateKeyContainer,\n                    _certificateFilePath,\n                    _certificateFilePassword,\n                    _isMachineKeyContainer,\n                    _isInteractive);\n            }\n\n            return _certificateStoreService;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.SignatureProviders.CertificateStore {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.SignatureProviders.CertificateStore.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unable to find a matching certificate..\n        /// </summary>\n        internal static string CertificateNotFound {\n            get {\n                return ResourceManager.GetString(\"CertificateNotFound\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unable to find a certificate with a matching {0} fingerprint in {1}..\n        /// </summary>\n        internal static string CertificateNotFoundInFile {\n            get {\n                return ResourceManager.GetString(\"CertificateNotFoundInFile\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unable to find a matching certificate in machine certificate store..\n        /// </summary>\n        internal static string CertificateNotFoundInMachineStore {\n            get {\n                return ResourceManager.GetString(\"CertificateNotFoundInMachineStore\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unable to find a matching certificate in user certificate store..\n        /// </summary>\n        internal static string CertificateNotFoundInUserStore {\n            get {\n                return ResourceManager.GetString(\"CertificateNotFoundInUserStore\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Unable to acquire RSA private key for the provided certificate..\n        /// </summary>\n        internal static string CertificateRSANotFound {\n            get {\n                return ResourceManager.GetString(\"CertificateRSANotFound\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetched certificate from certificate store. [{milliseconds} ms].\n        /// </summary>\n        internal static string FetchedCertificateFromCertificateStore {\n            get {\n                return ResourceManager.GetString(\"FetchedCertificateFromCertificateStore\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetched certificate from file. [{milliseconds} ms].\n        /// </summary>\n        internal static string FetchedCertificateFromFile {\n            get {\n                return ResourceManager.GetString(\"FetchedCertificateFromFile\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetching certificate from certificate store..\n        /// </summary>\n        internal static string FetchingCertificateFromCertificateStore {\n            get {\n                return ResourceManager.GetString(\"FetchingCertificateFromCertificateStore\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetching certificate from file..\n        /// </summary>\n        internal static string FetchingCertificateFromFile {\n            get {\n                return ResourceManager.GetString(\"FetchingCertificateFromFile\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The certificate has an unsupported public key algorithm..\n        /// </summary>\n        internal static string UnsupportedPublicKeyAlgorithm {\n            get {\n                return ResourceManager.GetString(\"UnsupportedPublicKeyAlgorithm\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"CertificateNotFound\" xml:space=\"preserve\">\n    <value>Unable to find a matching certificate.</value>\n  </data>\n  <data name=\"CertificateNotFoundInFile\" xml:space=\"preserve\">\n    <value>Unable to find a certificate with a matching {0} fingerprint in {1}.</value>\n    <comment>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</comment>\n  </data>\n  <data name=\"CertificateNotFoundInMachineStore\" xml:space=\"preserve\">\n    <value>Unable to find a matching certificate in machine certificate store.</value>\n  </data>\n  <data name=\"CertificateNotFoundInUserStore\" xml:space=\"preserve\">\n    <value>Unable to find a matching certificate in user certificate store.</value>\n  </data>\n  <data name=\"CertificateRSANotFound\" xml:space=\"preserve\">\n    <value>Unable to acquire RSA private key for the provided certificate.</value>\n  </data>\n  <data name=\"UnsupportedPublicKeyAlgorithm\" xml:space=\"preserve\">\n    <value>The certificate has an unsupported public key algorithm.</value>\n  </data>\n  <data name=\"FetchingCertificateFromFile\" xml:space=\"preserve\">\n    <value>Fetching certificate from file.</value>\n  </data>\n  <data name=\"FetchingCertificateFromCertificateStore\" xml:space=\"preserve\">\n    <value>Fetching certificate from certificate store.</value>\n  </data>\n  <data name=\"FetchedCertificateFromCertificateStore\" xml:space=\"preserve\">\n    <value>Fetched certificate from certificate store. [{milliseconds} ms]</value>\n    <comment>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</comment>\n  </data>\n  <data name=\"FetchedCertificateFromFile\" xml:space=\"preserve\">\n    <value>Fetched certificate from file. [{milliseconds} ms]</value>\n    <comment>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</comment>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/Sign.SignatureProviders.CertificateStore.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsShipping>true</IsShipping>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Sign.Core\\Sign.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"sign\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.CertificateStore.Test\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Nepovedlo se najít odpovídající certifikát.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">V {1} nebylo možné najít certifikát s odpovídajícím digitálním otiskem {0}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">V úložišti certifikátů počítače nebylo možné najít odpovídající certifikát.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">V úložišti certifikátů uživatele nebylo možné najít odpovídající certifikát.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Pro poskytnutý certifikát se nepovedlo získat privátní klíč RSA.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certifikát se načetl z úložiště certifikátů. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certifikát se načetl ze souboru. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Certifikát se načítá z úložiště certifikátů.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Certifikát se načítá ze souboru.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Certifikát má nepodporovaný algoritmus veřejného klíče.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Es wurde kein übereinstimmendes Zertifikat gefunden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Es wurde kein Zertifikat mit einem übereinstimmenden {0}-Fingerabdruck in {1} gefunden.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Im Computerzertifikatspeicher wurde kein übereinstimmendes Zertifikat gefunden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Im Benutzerzertifikatspeicher wurde kein übereinstimmendes Zertifikat gefunden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Der private RSA-Schlüssel für das angegebene Zertifikat kann nicht abgerufen werden.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Das Zertifikat wurde aus dem Zertifikatspeicher abgerufen. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Das Zertifikat wurde aus der Datei abgerufen. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Das Zertifikat wird aus dem Zertifikatspeicher abgerufen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Das Zertifikat wird aus der Datei abgerufen.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Das Zertifikat verfügt über einen nicht unterstützten Algorithmus für öffentliche Schlüssel.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">No se pudo encontrar ningún certificado que coincida.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">No se pudo encontrar ningún certificado con una huella digital {0} coincidente en {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">No se pudo encontrar un certificado correspondiente en el almacén de certificados de máquina.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">No se pudo encontrar un certificado correspondiente en el almacén de certificados de usuario.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">No se puede adquirir la clave privada RSA para el certificado proporcionado.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado capturado del almacén de certificados. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado capturado del archivo. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Capturando el certificado del almacén de certificados.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Capturando certificado del archivo.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">El certificado tiene un algoritmo de clave pública no admitido.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Désolé... Nous ne pouvons pas trouver un certificat correspondant.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Impossible de trouver un certificat avec une empreinte digitale {0} correspondante dans {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Désolé... Nous ne pouvons pas trouver un certificat correspondant dans le magasin de certificats de machine.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Désolé... Nous ne pouvons pas trouver un certificat correspondant dans le magasin de certificats d’utilisateur.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Désolé.... Nous ne pouvons pas acquérir la clé privée RSA pour le certificat fourni.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificat récupéré à partir du magasin de certificats. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificat récupéré à partir du fichier. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Récupération d’un certificat à partir du magasin de certificats.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Récupération d’un certificat à partir du fichier.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Le certificat possède un algorithme de clé publique non pris en charge.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Impossibile trovare un certificato corrispondente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Non è possibile trovare un certificato con un'impronta digitale {0} corrispondente in {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Impossibile trovare un certificato corrispondente nell'archivio certificati del computer.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Impossibile trovare un certificato corrispondente nell'archivio certificati dell'utente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Impossibile acquisire la chiave privata RSA per il certificato fornito.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Il certificato è stato recuperato dall'archivio certificati. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Il certificato è stato recuperato dal file. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Recupero del certificato dall'archivio certificati.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Recupero del certificato dal file in corso.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Il certificato contiene un algoritmo a chiave pubblica non supportato.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">一致する証明書が見つかりません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">{1} で、{0} フィンガープリントが一致する証明書が見つかりません。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">コンピューター証明書ストアに一致する証明書が見つかりません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">ユーザー証明書ストアに一致する証明書が見つかりません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">指定された証明書の RSA 秘密キーを取得できません。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">証明書ストアから証明書をフェッチしました。[{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">ファイルから証明書をフェッチしました。[{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">証明書ストアから証明書をフェッチしています。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">ファイルから証明書をフェッチしています。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">証明書にサポートされていない公開キー アルゴリズムがあります。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">일치하는 인증서를 찾을 수 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">{1}에서 일치하는 {0} 지문이 있는 인증서를 찾을 수 없습니다.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">컴퓨터 인증서 저장소에서 일치하는 인증서를 찾을 수 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">사용자 인증서 저장소에서 일치하는 인증서를 찾을 수 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">제공된 인증서의 RSA 프라이빗 키를 가져올 수 없습니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">인증서 저장소에서 인증서를 가져왔습니다. [{milliseconds}초]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">파일에서 인증서를 가져왔습니다. [{milliseconds}초]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">인증서 저장소에서 인증서를 가져오는 중입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">파일에서 인증서를 가져오는 중입니다.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">인증서에 지원되지 않는 공개 키 알고리즘이 있습니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Nie można znaleźć zgodnego certyfikatu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Nie można odnaleźć certyfikatu z pasującym {0} odciskiem palca w {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Nie można znaleźć zgodnego certyfikatu w magazynie certyfikatów komputera.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Nie można znaleźć zgodnego certyfikatu w magazynie certyfikatów użytkownika.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Nie można uzyskać klucza prywatnego RSA dla podanego certyfikatu.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Pobrano certyfikat z magazynu certyfikatów. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Pobrano certyfikat z pliku. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Pobieranie certyfikatu z magazynu certyfikatów.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Pobieranie certyfikatu z pliku.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Certyfikat zawiera nieobsługiwany algorytmu kluczy publicznych.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Não foi possível localizar um certificado correspondente.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Não é possível localizar um certificado com uma impressão digital correspondente {0} em {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Não foi possível localizar um certificado correspondente no repositório de certificados do computador.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Não foi possível localizar um certificado correspondente no repositório de certificados do usuário.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Não foi possível adquirir a chave privada RSA para o certificado fornecido.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado buscado do repositório de certificados. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado buscado do arquivo. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Buscando certificado do repositório de certificados.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Buscando certificado do arquivo.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">O certificado tem um algoritmo de chave pública sem suporte.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Не удается найти соответствующий сертификат.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">Не удалось найти сертификат с совпадающим отпечатком {0} в {1}.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Не удается найти соответствующий сертификат в хранилище сертификатов компьютера.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Не удается найти соответствующий сертификат в хранилище сертификатов пользователя.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Не удалось получить закрытый ключ RSA для предоставленного сертификата.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Извлечен сертификат из хранилища сертификатов. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Извлечен сертификат из файла. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Извлечение сертификата из хранилища сертификатов.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Извлечение сертификата из файла.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Сертификат содержит неподдерживаемый алгоритм открытого ключа.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">Eşleşen sertifika bulunamadı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">{1} dosya yolunda eşleşen {0} parmak izine sahip sertifika bulunamadı.</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">Makine sertifikası deposunda eşleşen bir sertifika bulunamadı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">Kullanıcı sertifikası deposunda eşleşen bir sertifika bulunamadı.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">Sağlanan sertifika için RSA özel anahtarı alınamıyor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">Sertifika, sertifika depolama alanından getirildi. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">Sertifika dosyadan getirildi. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">Sertifika, sertifika depolama alanından getiriliyor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">Sertifika, dosyadan getiriliyor.</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">Sertifika, desteklenmeyen ortak anahtar algoritmasına sahip.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">找不到匹配的证书。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">在 {1} 中找不到具有匹配的 {0} 指纹的证书。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">在计算机证书存储中找不到匹配的证书。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">在用户证书存储中找不到匹配的证书。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">无法获取所提供的证书的 RSA 私钥。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">已从证书存储中提取证书。[{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">已从文件中提取证书。[{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">正在从证书存储中提取证书。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">正在从文件中提取证书。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">证书具有不受支持的公钥算法。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.CertificateStore/xlf/Resources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateNotFound\">\n        <source>Unable to find a matching certificate.</source>\n        <target state=\"translated\">找不到相符的憑證。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInFile\">\n        <source>Unable to find a certificate with a matching {0} fingerprint in {1}.</source>\n        <target state=\"translated\">在 {1} 中找不到具有相符 {0} 指紋的憑證。</target>\n        <note>{NumberedPlaceholder=\"{0}\"} is a cryptographic algorithm.  {NumberedPlaceholder=\"{1}\"} is a file path.</note>\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInMachineStore\">\n        <source>Unable to find a matching certificate in machine certificate store.</source>\n        <target state=\"translated\">無法在機器憑證存放區中找到相符的憑證。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateNotFoundInUserStore\">\n        <source>Unable to find a matching certificate in user certificate store.</source>\n        <target state=\"translated\">無法在使用者憑證存放區中找到相符的憑證。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"CertificateRSANotFound\">\n        <source>Unable to acquire RSA private key for the provided certificate.</source>\n        <target state=\"translated\">無法取得所提供憑證的 RSA 私密金鑰。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromCertificateStore\">\n        <source>Fetched certificate from certificate store. [{milliseconds} ms]</source>\n        <target state=\"translated\">已從憑證存放區擷取憑證。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificateFromFile\">\n        <source>Fetched certificate from file. [{milliseconds} ms]</source>\n        <target state=\"translated\">已從檔案擷取憑證。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromCertificateStore\">\n        <source>Fetching certificate from certificate store.</source>\n        <target state=\"translated\">正在從憑證存放區擷取憑證。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificateFromFile\">\n        <source>Fetching certificate from file.</source>\n        <target state=\"translated\">正在從檔案擷取憑證。</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"UnsupportedPublicKeyAlgorithm\">\n        <source>The certificate has an unsupported public key algorithm.</source>\n        <target state=\"translated\">憑證具有不支援的公開金鑰演算法。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/KeyVaultService.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Azure;\nusing Azure.Security.KeyVault.Certificates;\nusing Azure.Security.KeyVault.Keys.Cryptography;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.KeyVault\n{\n    internal sealed class KeyVaultService : ISignatureAlgorithmProvider, ICertificateProvider, IDisposable\n    {\n        private readonly CertificateClient _certificateClient;\n        private readonly CryptographyClient _cryptographyClient;\n        private readonly string _certificateName;\n        private readonly ILogger<KeyVaultService> _logger;\n        private readonly SemaphoreSlim _mutex = new(1);\n        private X509Certificate2? _certificate;\n\n        internal KeyVaultService(\n            CertificateClient certificateClient,\n            CryptographyClient cryptographyClient,\n            string certificateName,\n            ILogger<KeyVaultService> logger)\n        {\n            ArgumentNullException.ThrowIfNull(certificateClient, nameof(certificateClient));\n            ArgumentNullException.ThrowIfNull(cryptographyClient, nameof(cryptographyClient));\n            ArgumentException.ThrowIfNullOrEmpty(certificateName, nameof(certificateName));\n            ArgumentNullException.ThrowIfNull(logger, nameof(logger));\n\n            _certificateName = certificateName;\n            _certificateClient = certificateClient;\n            _cryptographyClient = cryptographyClient;\n            _logger = logger;\n        }\n\n        public void Dispose()\n        {\n            _mutex.Dispose();\n            _certificate?.Dispose();\n            GC.SuppressFinalize(this);\n        }\n\n        public async Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken)\n        {\n            if (_certificate is not null)\n            {\n                return new X509Certificate2(_certificate); // clone it as it's disposable\n            }\n\n            await _mutex.WaitAsync(cancellationToken);\n\n            try\n            {\n                if (_certificate is null)\n                {\n                    Stopwatch stopwatch = Stopwatch.StartNew();\n\n                    _logger.LogTrace(Resources.FetchingCertificate);\n\n                    Response<KeyVaultCertificateWithPolicy> response = await _certificateClient.GetCertificateAsync(_certificateName, cancellationToken);\n\n                    _logger.LogTrace(Resources.FetchedCertificate, stopwatch.Elapsed.TotalMilliseconds);\n\n                    _certificate = new X509Certificate2(response.Value.Cer);\n\n                    //print the certificate info\n                    _logger.LogTrace($\"{Resources.CertificateDetails}{Environment.NewLine}{_certificate.ToString(verbose: true)}\");\n                }\n            }\n            finally\n            {\n                _mutex.Release();\n            }\n\n            return new X509Certificate2(_certificate); // clone it as it's disposable\n        }\n\n        public async Task<RSA> GetRsaAsync(CancellationToken cancellationToken)\n        {\n            using X509Certificate2 certificate = await GetCertificateAsync(cancellationToken);\n            RSAKeyVault rsaKeyVault = await _cryptographyClient.CreateRSAAsync(cancellationToken);\n            RSA rsaPublicKey = certificate.GetRSAPublicKey()!;\n            return new RSAKeyVaultWrapper(rsaKeyVault, rsaPublicKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/KeyVaultServiceProvider.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Sign.Core;\n\nnamespace Sign.SignatureProviders.KeyVault\n{\n    internal sealed class KeyVaultServiceProvider : ISignatureProvider\n    {\n        public ISignatureAlgorithmProvider GetSignatureAlgorithmProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return serviceProvider.GetRequiredService<KeyVaultService>();\n        }\n\n        public ICertificateProvider GetCertificateProvider(IServiceProvider serviceProvider)\n        {\n            ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));\n\n            return serviceProvider.GetRequiredService<KeyVaultService>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/RSAKeyVaultWrapper.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Azure.Security.KeyVault.Keys.Cryptography;\n\nnamespace Sign.SignatureProviders.KeyVault\n{\n    internal sealed class RSAKeyVaultWrapper : RSA\n    {\n        private readonly RSAKeyVault _rsaKeyVault;\n        private readonly RSA _rsaPublicKey;\n\n        public RSAKeyVaultWrapper(RSAKeyVault rsaKeyVault, RSA rsaPublicKey)\n        {\n            ArgumentNullException.ThrowIfNull(rsaKeyVault, nameof(rsaKeyVault));\n            ArgumentNullException.ThrowIfNull(rsaPublicKey, nameof(rsaPublicKey));\n\n            _rsaKeyVault = rsaKeyVault;\n            _rsaPublicKey = rsaPublicKey;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                _rsaKeyVault.Dispose();\n                _rsaPublicKey.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n\n        public override RSAParameters ExportParameters(bool includePrivateParameters)\n        {\n            if (includePrivateParameters)\n            {\n                throw new NotSupportedException();\n            }\n\n            return _rsaPublicKey.ExportParameters(false);\n        }\n\n        public override void ImportParameters(RSAParameters parameters)\n            => throw new NotImplementedException();\n\n        public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)\n            => _rsaKeyVault.SignHash(hash, hashAlgorithm, padding);\n\n        public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)\n            => _rsaPublicKey.VerifyHash(hash, signature, hashAlgorithm, padding);\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Sign.SignatureProviders.KeyVault {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Sign.SignatureProviders.KeyVault.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Certificate Details:.\n        /// </summary>\n        internal static string CertificateDetails {\n            get {\n                return ResourceManager.GetString(\"CertificateDetails\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetched certificate. [{milliseconds} ms].\n        /// </summary>\n        internal static string FetchedCertificate {\n            get {\n                return ResourceManager.GetString(\"FetchedCertificate\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Fetching certificate from Azure Key Vault..\n        /// </summary>\n        internal static string FetchingCertificate {\n            get {\n                return ResourceManager.GetString(\"FetchingCertificate\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"CertificateDetails\" xml:space=\"preserve\">\n    <value>Certificate details:</value>\n  </data>\n  <data name=\"FetchedCertificate\" xml:space=\"preserve\">\n    <value>Fetched certificate. [{milliseconds} ms]</value>\n    <comment>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</comment>\n  </data>\n  <data name=\"FetchingCertificate\" xml:space=\"preserve\">\n    <value>Fetching certificate from Azure Key Vault.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/Sign.SignatureProviders.KeyVault.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsShipping>true</IsShipping>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"Azure.Security.KeyVault.Certificates\" />\n    <PackageReference Include=\"Azure.Security.KeyVault.Keys\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Sign.Core\\Sign.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"sign\" />\n    <InternalsVisibleTo Include=\"Sign.SignatureProviders.KeyVault.Test\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.cs.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"cs\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Podrobnosti certifikátu:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Načetl se certifikát. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Načítá se certifikát z Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.de.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"de\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Zertifikatdetails:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Zertifikat abgerufen. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Zertifikat wird von Azure Key Vault abgerufen.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.es.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"es\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Detalles del certificado:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado capturado. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Capturando certificado de Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.fr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"fr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Détails du certificat :</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificat récupéré. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Récupération du certificat à partir d’Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.it.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"it\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Dettagli certificato:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Il certificato è stato recuperato. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Recupero certificato da Azure Key Vault in corso.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.ja.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ja\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">証明書の詳細:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">証明書をフェッチしました。[{milliseconds} ミリ秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault から証明書をフェッチしています。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.ko.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ko\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">인증서 세부 정보:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">인증서를 가져왔습니다. [{milliseconds}ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Azure Key Vault에서 인증서를 가져오는 중입니다.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.pl.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pl\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Szczegóły certyfikatu:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Pobrano certyfikat. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Pobieranie certyfikatu z usługi Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.pt-BR.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"pt-BR\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Detalhes do certificado:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Certificado buscado. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Buscando certificado no Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.ru.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"ru\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Сведения о сертификате:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Получен сертификат. [{milliseconds} мс]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Идет получение сертификата из Azure Key Vault.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.tr.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"tr\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">Sertifika ayrıntıları:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">Sertifika getirildi. [{milliseconds} ms]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">Sertifika Azure Key Vault’tan getiriliyor.</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.zh-Hans.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hans\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">证书详细信息:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">已提取证书。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">正在从 Azure Key Vault 提取证书。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "src/Sign.SignatureProviders.KeyVault/xlf/Resources.zh-Hant.xlf",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.2\" xsi:schemaLocation=\"urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd\">\n  <file datatype=\"xml\" source-language=\"en\" target-language=\"zh-Hant\" original=\"../Resources.resx\">\n    <body>\n      <trans-unit id=\"CertificateDetails\">\n        <source>Certificate details:</source>\n        <target state=\"translated\">憑證詳細資料:</target>\n        <note />\n      </trans-unit>\n      <trans-unit id=\"FetchedCertificate\">\n        <source>Fetched certificate. [{milliseconds} ms]</source>\n        <target state=\"translated\">已擷取憑證。[{milliseconds} 毫秒]</target>\n        <note>{Placeholder=\"{milliseconds}\"} is a decimal number representing the number of milliseconds elapsed, and \"ms\" is the unit abbreviation for milliseconds.</note>\n      </trans-unit>\n      <trans-unit id=\"FetchingCertificate\">\n        <source>Fetching certificate from Azure Key Vault.</source>\n        <target state=\"translated\">正在從 Azure Key Vault 擷取憑證。</target>\n        <note />\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"
  },
  {
    "path": "test/Sign.Cli.Test/ArtifactSigningCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public class ArtifactSigningCommandTests\n    {\n        private readonly ArtifactSigningCommand _command = new(new CodeCommand(), Mock.Of<IServiceProviderFactory>());\n\n        [Fact]\n        public void Constructor_WhenCodeCommandIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningCommand(codeCommand: null!, Mock.Of<IServiceProviderFactory>()));\n\n            Assert.Equal(\"codeCommand\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderFactoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningCommand(new CodeCommand(), serviceProviderFactory: null!));\n\n            Assert.Equal(\"serviceProviderFactory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void EndpointOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.EndpointOption.Arity);\n        }\n\n        [Fact]\n        public void EndpointOption_Always_IsRequired()\n        {\n            Assert.True(_command.EndpointOption.Required);\n        }\n\n        [Fact]\n        public void AccountOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.AccountOption.Arity);\n        }\n\n        [Fact]\n        public void AccountOption_Always_IsRequired()\n        {\n            Assert.True(_command.AccountOption.Required);\n        }\n\n        [Fact]\n        public void CertificateProfileOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateProfileOption.Arity);\n        }\n\n        [Fact]\n        public void CertificateProfileOption_Always_IsRequired()\n        {\n            Assert.True(_command.CertificateProfileOption.Required);\n        }\n\n        public class ParserTests\n        {\n            private readonly ArtifactSigningCommand _command;\n            private readonly RootCommand _rootCommand;\n\n            public ParserTests()\n            {\n                CodeCommand codeCommand = new();\n                _command = new(codeCommand, Mock.Of<IServiceProviderFactory>());\n                _rootCommand = new RootCommand();\n                _rootCommand.Subcommands.Add(codeCommand);\n                codeCommand.Subcommands.Add(_command);\n            }\n\n            [Theory]\n            [InlineData(\"code artifact-signing\")]\n            [InlineData(\"code artifact-signing a\")]\n            [InlineData(\"code artifact-signing -ase\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c -kvi\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c -kvi d\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c -kvi d -kvs\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c -kvi d -kvs e\")]\n            public void Command_WhenRequiredArgumentOrOptionsAreMissing_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b -kvt c -kvi d -kvs e f\")]\n            public void Command_WhenRequiredArgumentsArePresent_HasNoError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code artifact-signing -ase \\\"\\\" -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase //artifactsigning.test -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase /path -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase file:///file.bin -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase http://artifactsigning.test -asa a -ascp b c\")]\n            [InlineData(\"code artifact-signing -ase ftp://artifactsigning.test -asa a -ascp b c\")]\n            public void Command_WhenEndpointUrlIsInvalid_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n                Assert.Contains(result.Errors, error => error.Message.Contains(\"URL\"));\n            }\n\n            [Theory]\n            [InlineData(\"code artifact-signing -ase https://artifactsigning.test -asa a -ascp b c\", \"https://artifactsigning.test/\")]\n            [InlineData(\"code artifact-signing -ase HTTPS://ARTIFACTSIGNING.TEST -asa a -ascp b c\", \"https://artifactsigning.test/\")]\n            public void Command_WhenEndpointUrlIsValidHttps_ParsesCorrectly(string command, string expectedUrl)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n                Uri? actualUrl = result.GetValue(_command.EndpointOption);\n                Assert.NotNull(actualUrl);\n                Assert.Equal(expectedUrl, actualUrl.AbsoluteUri);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/AzureCredentialOptionsTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Azure.Core;\nusing Azure.Identity;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public class AzureCredentialOptionsTests\n    {\n        private readonly AzureCredentialOptions _options;\n        private readonly AzureKeyVaultCommand _command;\n        private readonly RootCommand _rootCommand;\n\n        public AzureCredentialOptionsTests()\n        {\n            CodeCommand codeCommand = new();\n            _command = new(codeCommand, Mock.Of<IServiceProviderFactory>());\n            _rootCommand = new RootCommand();\n            _rootCommand.Subcommands.Add(codeCommand);\n            codeCommand.Subcommands.Add(_command);\n            _options = _command.AzureCredentialOptions;\n        }\n\n        [Fact]\n        public void CredentialTypeOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.CredentialTypeOption.Arity);\n        }\n\n        [Fact]\n        public void CredentialTypeOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.CredentialTypeOption.Required);\n        }\n\n        [Fact]\n        public void CredentialTypeOption_Always_HasCorrectCompletions()\n        {\n            // Verify valid values are accepted\n            ParseResult result1 = _rootCommand.Parse(\"code azure-key-vault --azure-key-vault-url https://test --azure-key-vault-certificate cert --azure-credential-type azure-cli test.dll\");\n            Assert.Empty(result1.Errors);\n\n            ParseResult result2 = _rootCommand.Parse(\"code azure-key-vault --azure-key-vault-url https://test --azure-key-vault-certificate cert --azure-credential-type azure-powershell test.dll\");\n            Assert.Empty(result2.Errors);\n\n            ParseResult result3 = _rootCommand.Parse(\"code azure-key-vault --azure-key-vault-url https://test --azure-key-vault-certificate cert --azure-credential-type managed-identity test.dll\");\n            Assert.Empty(result3.Errors);\n\n            ParseResult result4 = _rootCommand.Parse(\"code azure-key-vault --azure-key-vault-url https://test --azure-key-vault-certificate cert --azure-credential-type workload-identity test.dll\");\n            Assert.Empty(result4.Errors);\n\n            // Verify invalid values are rejected\n            ParseResult result5 = _rootCommand.Parse(\"code azure-key-vault --azure-key-vault-url https://test --azure-key-vault-certificate cert --azure-credential-type invalid test.dll\");\n            Assert.NotEmpty(result5.Errors);\n        }\n\n        [Fact]\n        public void ManagedIdentityClientIdOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.ManagedIdentityClientIdOption.Arity);\n        }\n\n        [Fact]\n        public void ManagedIdentityClientIdOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ManagedIdentityClientIdOption.Required);\n        }\n\n        [Fact]\n        public void ManagedIdentityResourceIdOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.ManagedIdentityResourceIdOption.Arity);\n        }\n\n        [Fact]\n        public void ManagedIdentityResourceIdOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ManagedIdentityResourceIdOption.Required);\n        }\n\n        [Fact]\n        public void ObsoleteManagedIdentityOption_Always_HasArityOfZeroOrOne()\n        {\n            Assert.Equal(ArgumentArity.ZeroOrOne, _options.ObsoleteManagedIdentityOption.Arity);\n        }\n\n        [Fact]\n        public void ObsoleteManagedIdentityOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ObsoleteManagedIdentityOption.Required);\n        }\n\n        [Fact]\n        public void ObsoleteManagedIdentityOption_Always_IsHidden()\n        {\n            Assert.True(_options.ObsoleteManagedIdentityOption.Hidden);\n        }\n\n        [Fact]\n        public void ObsoleteTenantIdOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.ObsoleteTenantIdOption.Arity);\n        }\n\n        [Fact]\n        public void ObsoleteTenantIdOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ObsoleteTenantIdOption.Required);\n        }\n\n        [Fact]\n        public void ObsoleteTenantIdOption_Always_IsHidden()\n        {\n            Assert.True(_options.ObsoleteTenantIdOption.Hidden);\n        }\n\n        [Fact]\n        public void ObsoleteClientIdOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.ObsoleteClientIdOption.Arity);\n        }\n\n        [Fact]\n        public void ObsoleteClientIdOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ObsoleteClientIdOption.Required);\n        }\n\n        [Fact]\n        public void ObsoleteClientIdOption_Always_IsHidden()\n        {\n            Assert.True(_options.ObsoleteClientIdOption.Hidden);\n        }\n\n        [Fact]\n        public void ObsoleteClientSecretOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _options.ObsoleteClientSecretOption.Arity);\n        }\n\n        [Fact]\n        public void ObsoleteClientSecretOption_Always_IsNotRequired()\n        {\n            Assert.False(_options.ObsoleteClientSecretOption.Required);\n        }\n\n        [Fact]\n        public void ObsoleteClientSecretOption_Always_IsHidden()\n        {\n            Assert.True(_options.ObsoleteClientSecretOption.Hidden);\n        }\n\n        [Fact]\n        public void AddOptionsToCommand_Always_AddsAllOptionsToCommand()\n        {\n            var command = new Command(\"test\");\n\n            _options.AddOptionsToCommand(command);\n\n            Assert.Contains(_options.CredentialTypeOption, command.Options);\n            Assert.Contains(_options.ManagedIdentityClientIdOption, command.Options);\n            Assert.Contains(_options.ManagedIdentityResourceIdOption, command.Options);\n            Assert.Contains(_options.ObsoleteManagedIdentityOption, command.Options);\n            Assert.Contains(_options.ObsoleteTenantIdOption, command.Options);\n            Assert.Contains(_options.ObsoleteClientIdOption, command.Options);\n            Assert.Contains(_options.ObsoleteClientSecretOption, command.Options);\n        }\n\n        [Fact]\n        public void CreateDefaultAzureCredentialOptions_WhenManagedIdentityClientIdIsSpecified_ManagedIdentityClientIdIsSet()\n        {\n            ParseResult result = _rootCommand.Parse(@\"code azure-key-vault -kvu https://keyvault.test -kvc a -mici b c\");\n\n            DefaultAzureCredentialOptions credentialOptions = _options.CreateDefaultAzureCredentialOptions(result);\n\n            Assert.Equal(\"b\", credentialOptions.ManagedIdentityClientId);\n        }\n\n        [Fact]\n        public void CreateDefaultAzureCredentialOptions_WhenManagedIdentityResourceIdIsSpecified_ManagedIdentityResourceIdIsSet()\n        {\n            ParseResult result = _rootCommand.Parse(@\"code azure-key-vault -kvu https://keyvault.test -kvc a -miri b c\");\n\n            DefaultAzureCredentialOptions credentialOptions = _options.CreateDefaultAzureCredentialOptions(result);\n\n            Assert.Equal(\"b\", credentialOptions.ManagedIdentityResourceId);\n        }\n\n        [Fact]\n        public void CreateDefaultAzureCredentialOptions_WhenNoOptionsAreSpecified_ExcludeOptionsHaveTheCorrectDefaultValues()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a b\");\n\n            DefaultAzureCredentialOptions credentialOptions = _options.CreateDefaultAzureCredentialOptions(result);\n\n            Assert.True(credentialOptions.ExcludeInteractiveBrowserCredential);\n            Assert.False(credentialOptions.ExcludeAzureCliCredential);\n            Assert.False(credentialOptions.ExcludeAzureDeveloperCliCredential);\n            Assert.False(credentialOptions.ExcludeAzurePowerShellCredential);\n            Assert.False(credentialOptions.ExcludeEnvironmentCredential);\n            Assert.False(credentialOptions.ExcludeManagedIdentityCredential);\n            Assert.False(credentialOptions.ExcludeVisualStudioCredential);\n            Assert.False(credentialOptions.ExcludeWorkloadIdentityCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenClientSecretOptionsAreSet_ReturnsClientSecretCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c -kvs d e\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<ClientSecretCredential>(tokenCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenCredentialTypeIsAzureCli_ReturnsAzureCliCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a -act azure-cli b\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<AzureCliCredential>(tokenCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenCredentialTypeIsAzurePowerShell_ReturnsAzurePowerShellCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a -act azure-powershell b\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<AzurePowerShellCredential>(tokenCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenCredentialTypeIsManagedIdentity_ReturnsManagedIdentityCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a -act managed-identity b\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<ManagedIdentityCredential>(tokenCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenCredentialTypeIsWorkloadIdentity_ReturnsWorkloadIdentityCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a -act workload-identity b\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<WorkloadIdentityCredential>(tokenCredential);\n        }\n\n        [Fact]\n        public void CreateTokenCredential_WhenCredentialTypeIsNotSet_ReturnsDefaultAzureCredential()\n        {\n            ParseResult result = _rootCommand.Parse(\"code azure-key-vault -kvu https://keyvault.test -kvc a b\");\n\n            TokenCredential? tokenCredential = _options.CreateTokenCredential(result);\n\n            Assert.IsType<DefaultAzureCredential>(tokenCredential);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/AzureKeyVaultCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public class AzureKeyVaultCommandTests\n    {\n        private readonly AzureKeyVaultCommand _command = new(new CodeCommand(), Mock.Of<IServiceProviderFactory>());\n\n        [Fact]\n        public void Constructor_WhenCodeCommandIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AzureKeyVaultCommand(codeCommand: null!, Mock.Of<IServiceProviderFactory>()));\n\n            Assert.Equal(\"codeCommand\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderFactoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AzureKeyVaultCommand(new CodeCommand(), serviceProviderFactory: null!));\n\n            Assert.Equal(\"serviceProviderFactory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CertificateOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateOption.Arity);\n        }\n\n        [Fact]\n        public void CertificateOption_Always_IsRequired()\n        {\n            Assert.True(_command.CertificateOption.Required);\n        }\n\n        [Fact]\n        public void UrlOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.UrlOption.Arity);\n        }\n\n        [Fact]\n        public void UrlOption_Always_IsRequired()\n        {\n            Assert.True(_command.UrlOption.Required);\n        }\n\n        public class ParserTests\n        {\n            private readonly AzureKeyVaultCommand _command;\n            private readonly RootCommand _rootCommand;\n\n            public ParserTests()\n            {\n                CodeCommand codeCommand = new();\n                _command = new(codeCommand, Mock.Of<IServiceProviderFactory>());\n                _rootCommand = new RootCommand();\n                _rootCommand.Subcommands.Add(codeCommand);\n                codeCommand.Subcommands.Add(_command);\n            }\n\n            [Theory]\n            [InlineData(\"code azure-key-vault\")]\n            [InlineData(\"code azure-key-vault a\")]\n            [InlineData(\"code azure-key-vault -kvu\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test a\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c -kvs\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c -kvs d\")]\n            public void Command_WhenRequiredArgumentOrOptionsAreMissing_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c -kvs d e\")]\n            public void Command_WhenRequiredArgumentsArePresent_HasNoError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code azure-key-vault -kvu \\\"\\\" -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu //keyvault.test -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu /path -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu file:///file.bin -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu http://keyvault.test -kvc a b\")]\n            [InlineData(\"code azure-key-vault -kvu ftp://keyvault.test -kvc a b\")]\n            public void Command_WhenUrlIsInvalid_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n                Assert.Contains(result.Errors, error => error.Message.Contains(\"URL\"));\n            }\n\n            [Theory]\n            [InlineData(\"code azure-key-vault -kvu https://keyvault.test -kvc a b\", \"https://keyvault.test/\")]\n            [InlineData(\"code azure-key-vault -kvu https://my-vault.vault.azure.test -kvc cert b\", \"https://my-vault.vault.azure.test/\")]\n            [InlineData(\"code azure-key-vault -kvu HTTPS://KEYVAULT.TEST -kvc a b\", \"https://keyvault.test/\")]\n            public void Command_WhenUrlIsValidHttps_ParsesCorrectly(string command, string expectedUrl)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n                Uri? actualUrl = result.GetValue(_command.UrlOption);\n                Assert.NotNull(actualUrl);\n                Assert.Equal(expectedUrl, actualUrl.AbsoluteUri);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/CertificateStoreCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public class CertificateStoreCommandTests\n    {\n        private readonly CertificateStoreCommand _command = new(new CodeCommand(), Mock.Of<IServiceProviderFactory>());\n\n        private const string Sha1Fingerprint = \"da39a3ee5e6b4b0d3255bfef95601890afd80709\";\n        private const string Sha256Fingerprint = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n        private const string Sha384Fingerprint = \"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b\";\n        private const string Sha512Fingerprint = \"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\";\n\n        [Fact]\n        public void Constructor_WhenCodeCommandIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreCommand(codeCommand: null!, Mock.Of<IServiceProviderFactory>()));\n\n            Assert.Equal(\"codeCommand\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderFactoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreCommand(new CodeCommand(), serviceProviderFactory: null!));\n\n            Assert.Equal(\"serviceProviderFactory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CertificateFingerprintOption_Always_IsRequired()\n        {\n            Assert.True(_command.CertificateFingerprintOption.Required);\n        }\n\n        [Fact]\n        public void CertificateFingerprintOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateFingerprintOption.Arity);\n        }\n\n        [Fact]\n        public void CertificateFileOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateFileOption.Arity);\n        }\n\n        [Fact]\n        public void CertificatePasswordOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificatePasswordOption.Arity);\n        }\n\n        [Fact]\n        public void CryptoServiceProviderOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CryptoServiceProviderOption.Arity);\n        }\n\n        [Fact]\n        public void PrivateKeyContainerOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.PrivateKeyContainerOption.Arity);\n        }\n\n        public class ParserTests\n        {\n            private readonly CertificateStoreCommand _command;\n            private readonly RootCommand _rootCommand;\n\n            public ParserTests()\n            {\n                CodeCommand codeCommand = new();\n                _command = new CertificateStoreCommand(codeCommand, Mock.Of<IServiceProviderFactory>());\n                _rootCommand = new RootCommand();\n                _rootCommand.Subcommands.Add(codeCommand);\n                codeCommand.Subcommands.Add(_command);\n            }\n\n            [Theory]\n            [InlineData(\"code certificate-store a\")]\n            [InlineData(\"code certificate-store a -cfp\")]\n            [InlineData(\"code certificate-store a -cfp -cf\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -p\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -csp\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -csp sampleCSP -k\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -csp\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -csp sampleCSP -k\")]\n            public void Command_WhenRequiredArgumentOrOptionsAreMissing_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code certificate-store a -cfp \\\"\\\"\")]\n            [InlineData(\"code certificate-store a -cfp b\")]\n            [InlineData(\"code certificate-store a -cfp b c\")]\n            [InlineData($\"code certificate-store a -cfp {Sha1Fingerprint}\")]\n            [InlineData(\"code certificate-store a -cfp Z3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\")] // SHA-256 length, but contains a non-hex character\n            public void Command_WhenCertificateFingerprintAlgorithmCannotBeDeduced_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint}\")]\n            [InlineData($\"code certificate-store a -cfp {Sha384Fingerprint} -cf filePath\")]\n            [InlineData($\"code certificate-store a -cfp {Sha512Fingerprint} -cf filePath -p password\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -csp sampleCSP -k keyContainer \")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -csp sampleCSP -k machineKeyContainer -km\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -csp sampleCSP -k keyContainer \")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -p password -csp sampleCSP -k keyContainer\")]\n            [InlineData($\"code certificate-store a -cfp {Sha256Fingerprint} -cf filePath -csp sampleCSP -k keyContainer -km\")]\n            public void Command_WhenRequiredArgumentsArePresent_HasNoError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/CodeCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public class CodeCommandTests\n    {\n        private readonly CodeCommand _command = new();\n\n        [Fact]\n        public void BaseDirectoryOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.BaseDirectoryOption.Arity);\n        }\n\n        [Fact]\n        public void BaseDirectoryOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.BaseDirectoryOption.Required);\n        }\n\n        [Fact]\n        public void DescriptionOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.DescriptionOption.Arity);\n        }\n\n        [Fact]\n        public void DescriptionOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.DescriptionOption.Required);\n        }\n\n        [Fact]\n        public void DescriptionUrlOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.DescriptionUrlOption.Arity);\n        }\n\n        [Fact]\n        public void DescriptionUrlOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.DescriptionUrlOption.Required);\n        }\n\n        [Fact]\n        public void FileDigestOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.FileDigestOption.Arity);\n        }\n\n        [Fact]\n        public void FileDigestOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.FileDigestOption.Required);\n        }\n\n        [Fact]\n        public void FileListOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.FileListOption.Arity);\n        }\n\n        [Fact]\n        public void FileListOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.FileListOption.Required);\n        }\n\n        [Fact]\n        public void MaxConcurrencyOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.MaxConcurrencyOption.Arity);\n        }\n\n        [Fact]\n        public void MaxConcurrencyOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.MaxConcurrencyOption.Required);\n        }\n\n        [Fact]\n        public void OutputOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.OutputOption.Arity);\n        }\n\n        [Fact]\n        public void OutputOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.OutputOption.Required);\n        }\n\n        [Fact]\n        public void PublisherNameOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.PublisherNameOption.Arity);\n        }\n\n        [Fact]\n        public void PublisherNameOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.PublisherNameOption.Required);\n        }\n\n        [Fact]\n        public void TimestampDigestOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.TimestampDigestOption.Arity);\n        }\n\n        [Fact]\n        public void TimestampDigestOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.TimestampDigestOption.Required);\n        }\n\n        [Fact]\n        public void TimestampUrlOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.TimestampUrlOption.Arity);\n        }\n\n        [Fact]\n        public void TimestampUrlOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.TimestampUrlOption.Required);\n        }\n\n        [Fact]\n        public void VerbosityOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.VerbosityOption.Arity);\n        }\n\n        [Fact]\n        public void VerbosityOption_Always_IsNotRequired()\n        {\n            Assert.False(_command.VerbosityOption.Required);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/ApplicationNameOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class ApplicationNameOptionTests : OptionTests<string?>\n    {\n        private const string? ExpectedValue = \"peach\";\n\n        public ApplicationNameOptionTests()\n            : base(new CodeCommand().ApplicationNameOption, \"-an\", \"--application-name\", ExpectedValue)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/BaseDirectoryOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.Globalization;\n\nnamespace Sign.Cli.Test\n{\n    public class BaseDirectoryOptionTests : DirectoryInfoOptionTests\n    {\n        public BaseDirectoryOptionTests()\n            : base(new CodeCommand().BaseDirectoryOption, \"-b\", \"--base-directory\")\n        {\n        }\n\n        [Fact]\n        public void Option_WhenOptionIsMissing_HasDefaultValue()\n        {\n            ParseResult result = Parse();\n            DirectoryInfo? value = result.GetValue(Option);\n\n            VerifyEqual(new DirectoryInfo(Environment.CurrentDirectory), value);\n        }\n\n        [Theory]\n        [InlineData(\"directory\")]\n        [InlineData(@\".\\directory\")]\n        public void Option_WhenValueIsNotRooted_HasError(string relativePath)\n        {\n            VerifyHasErrors(\n                $\"{LongOption} {relativePath}\",\n                string.Format(CultureInfo.CurrentCulture, Resources.InvalidBaseDirectoryValue, \"--base-directory\"));\n        }\n\n        [Fact]\n        public void Option_WhenValueIsRooted_ParsesValue()\n        {\n            DirectoryInfo directory = new(\".\");\n\n            Verify($\"{LongOption} \\\"{directory.FullName}\\\"\", directory);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/DescriptionOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class DescriptionOptionTests : OptionTests<string>\n    {\n        private const string ExpectedValue = \"peach\";\n\n        public DescriptionOptionTests()\n            : base(new CodeCommand().DescriptionOption, \"-d\", \"--description\", ExpectedValue)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/DescriptionUrlOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class DescriptionUrlOptionTests : UriOptionTests\n    {\n        public DescriptionUrlOptionTests()\n            : base(new CodeCommand().DescriptionUrlOption, \"-u\", \"--description-url\")\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/DirectoryInfoOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public abstract class DirectoryInfoOptionTests : OptionTests<DirectoryInfo>\n    {\n        private static readonly DirectoryInfo ExpectedValue = new(Path.GetTempPath());\n\n        protected DirectoryInfoOptionTests(Option<DirectoryInfo> option, string shortOption, string longOption)\n            : base(option, shortOption, longOption, ExpectedValue)\n        {\n        }\n\n        protected override void VerifyEqual(DirectoryInfo? expectedValue, DirectoryInfo? actualValue)\n        {\n            Assert.Equal(expectedValue?.FullName, actualValue?.FullName);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/FileDigestOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class FileDigestOptionTests : HashAlgorithmNameOptionTests\n    {\n        public FileDigestOptionTests()\n            : base(new CodeCommand().FileDigestOption, \"-fd\", \"--file-digest\")\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/HashAlgorithmNameOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.Security.Cryptography;\n\nnamespace Sign.Cli.Test\n{\n    public abstract class HashAlgorithmNameOptionTests : OptionTests<HashAlgorithmName>\n    {\n        private static readonly HashAlgorithmName ExpectedValue = HashAlgorithmName.SHA256;\n\n        protected HashAlgorithmNameOptionTests(Option<HashAlgorithmName> option, string shortOption, string longOption)\n            : base(option, shortOption, longOption, ExpectedValue)\n        {\n        }\n\n        [Theory]\n        [InlineData(\"Sha256\")]\n        [InlineData(\"SHA256\")]\n        public void Option_WhenValueIsSha256_ParsesValue(string value)\n        {\n            Verify($\"{LongOption} {value}\", HashAlgorithmName.SHA256);\n        }\n\n        [Theory]\n        [InlineData(\"Sha384\")]\n        [InlineData(\"SHA384\")]\n        public void Option_WhenValueIsSha384_ParsesValue(string value)\n        {\n            Verify($\"{LongOption} {value}\", HashAlgorithmName.SHA384);\n        }\n\n        [Theory]\n        [InlineData(\"Sha512\")]\n        [InlineData(\"SHA512\")]\n        public void Option_WhenValueIsSha512_ParsesValue(string value)\n        {\n            Verify($\"{LongOption} {value}\", HashAlgorithmName.SHA512);\n        }\n\n        [Theory]\n        [InlineData(\"md5\")]\n        [InlineData(\"sha1\")]\n        [InlineData(\"sha-256\")]\n        public void Verbosity_WhenValueIsInvalid_HasError(string value)\n        {\n            VerifyHasErrors(\n                $\"{LongOption} {value}\",\n                GetFormattedResourceString(Resources.InvalidDigestValue, LongOption));\n        }\n\n        [Fact]\n        public void Option_WhenOptionIsMissing_HasDefaultValue()\n        {\n            ParseResult result = Parse();\n            HashAlgorithmName value = result.GetValue(Option);\n\n            Assert.Equal(HashAlgorithmName.SHA256, value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/Int32OptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public abstract class Int32OptionTests : OptionTests<int>\n    {\n        private const int ExpectedValue = 3;\n\n        protected Int32OptionTests(Option<int> option, string shortOption, string longOption)\n            : base(option, shortOption, longOption, ExpectedValue)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/MaxConcurrencyOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public class MaxConcurrencyOptionTests : Int32OptionTests\n    {\n        public MaxConcurrencyOptionTests()\n            : base(new CodeCommand().MaxConcurrencyOption, \"-m\", \"--max-concurrency\")\n        {\n        }\n\n        [Fact]\n        public void Option_WhenValueFailsToParse_HasError()\n        {\n            const string value = \"x\";\n\n            VerifyHasErrors(value, GetUnrecognizedCommandOrArgumentMessage(value));\n        }\n\n        [Fact]\n        public void Option_WhenOptionIsMissing_HasDefaultValue()\n        {\n            ParseResult result = Parse();\n            int value = result.GetValue(Option);\n\n            Assert.Equal(4, value);\n        }\n\n        [Theory]\n        [InlineData(0)]\n        [InlineData(-1)]\n        public void Option_WhenValueIsLessThanOne_HasError(int value)\n        {\n            VerifyHasErrors(\n                $\"{LongOption} {value}\",\n                GetFormattedResourceString(Resources.InvalidMaxConcurrencyValue, LongOption));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/OptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.CommandLine.Parsing;\nusing System.Globalization;\n\nnamespace Sign.Cli.Test\n{\n    public abstract class OptionTests<T>\n    {\n        private readonly T? _expectedValue;\n\n        protected Option<T> Option { get; }\n        protected string LongOption { get; }\n        protected string ShortOption { get; }\n\n        protected OptionTests(Option<T> option, string shortOption, string longOption, T? expectedValue)\n        {\n            Option = option;\n            ShortOption = shortOption;\n            LongOption = longOption;\n            _expectedValue = expectedValue;\n        }\n\n        [Fact]\n        public void Option_WhenOptionIsMissing_HasParseErrorsOnlyIfRequired()\n        {\n            VerifyIsRequired();\n        }\n\n        [Fact]\n        public void Option_WithOnlyValue_HasParseErrors()\n        {\n            const string value = \"x\";\n\n            if (Option.Required)\n            {\n                VerifyHasErrors(\n                    value,\n                    GetOptionRequiredMessage(ShortOption),\n                    GetUnrecognizedCommandOrArgumentMessage(value));\n            }\n            else\n            {\n                VerifyHasErrors(value, GetUnrecognizedCommandOrArgumentMessage(value));\n            }\n        }\n\n        [Fact]\n        public void Option_WithShortOptionAndMissingValue_HasParseErrors()\n        {\n            VerifyHasErrors(ShortOption, GetRequiredArgumentMissingMessage(ShortOption));\n        }\n\n        [Fact]\n        public void Option_WithLongOptionAndMissingValue_HasParseErrors()\n        {\n            VerifyHasErrors(LongOption, GetRequiredArgumentMissingMessage(LongOption));\n        }\n\n        [Fact]\n        public void Option_WithShortOptionThenValue_ParsesValueOnlyIfShortOptionHasSingleCharacterAlias()\n        {\n            // From https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax#option-argument-delimiters\n            // \"A POSIX convention lets you omit the delimiter when you are specifying a single-character option alias.\"\n\n            string commandLine = $\"{ShortOption}{_expectedValue}\";\n\n            if (ShortOption.Length == 2)\n            {\n                Verify(commandLine);\n            }\n            else\n            {\n                VerifyHasErrors(commandLine, GetUnrecognizedCommandOrArgumentMessage(commandLine));\n            }\n        }\n\n        [Fact]\n        public void Option_WithShortOptionSpaceThenValue_ParsesValue()\n        {\n            Verify($\"{ShortOption} {_expectedValue}\");\n        }\n\n        [Fact]\n        public void Option_WithLongOptionSpaceThenValue_ParsesValue()\n        {\n            Verify($\"{LongOption} {_expectedValue}\");\n        }\n\n        protected void Verify(string commandLine)\n        {\n            Verify(commandLine, _expectedValue);\n        }\n\n        protected void Verify(string commandLine, T? expectedValue)\n        {\n            ParseResult result = Parse(commandLine);\n\n            Assert.Empty(result.Errors);\n\n            T? actualValue = result.GetValue(Option);\n\n            VerifyEqual(expectedValue, actualValue);\n        }\n\n        protected virtual void VerifyEqual(T? expectedValue, T? actualValue)\n        {\n            Assert.Equal(expectedValue, actualValue);\n        }\n\n        protected void VerifyHasErrors(string commandLine, params string[] expectedErrorMessages)\n        {\n            ParseResult result = Parse(commandLine);\n            HashSet<string> expectedMessages = new(expectedErrorMessages, StringComparer.Ordinal);\n            HashSet<string> actualMessages = result.Errors\n                .Select(error => error.Message)\n                .ToHashSet(StringComparer.Ordinal);\n\n            Assert.NotEmpty(actualMessages);\n            Assert.Equal(expectedMessages, actualMessages);\n        }\n\n        private void VerifyIsRequired()\n        {\n            ParseResult result = Parse();\n\n            if (Option.Required)\n            {\n                ParseError parseError = Assert.Single(result.Errors);\n                string actualMessage = parseError.Message;\n                string expectedMessage = GetOptionRequiredMessage(ShortOption);\n\n                Assert.Equal(expectedMessage, actualMessage);\n            }\n            else\n            {\n                Assert.Empty(result.Errors);\n            }\n        }\n\n        protected ParseResult Parse(string commandLine = \"\")\n        {\n            RootCommand rootCommand = new() { Option };\n\n            return rootCommand.Parse(commandLine);\n        }\n\n        protected static string GetFormattedResourceString(string resourceString, params string[] arguments)\n        {\n            return string.Format(CultureInfo.CurrentCulture, resourceString, arguments);\n        }\n\n        private static string GetRequiredArgumentMissingMessage(string argumentName)\n        {\n            return string.Format(\n                CultureInfo.CurrentCulture,\n                \"Required argument missing for option: '{0}'.\",\n                argumentName);\n        }\n\n        protected static string GetOptionRequiredMessage(string optionName)\n        {\n            return string.Format(\n                CultureInfo.CurrentCulture,\n                \"Option '{0}' is required.\",\n                optionName);\n        }\n\n        protected static string GetUnrecognizedCommandOrArgumentMessage(string name)\n        {\n            return string.Format(\n                CultureInfo.CurrentCulture,\n                \"Unrecognized command or argument '{0}'.\",\n                name);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/OutputOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class OutputOptionTests : OptionTests<string?>\n    {\n        private const string ExpectedValue = \"peach\";\n\n        public OutputOptionTests()\n            : base(new CodeCommand().OutputOption, \"-o\", \"--output\", ExpectedValue)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/PublisherNameOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class PublisherNameOptionTests : OptionTests<string?>\n    {\n        private const string? ExpectedValue = \"peach\";\n\n        public PublisherNameOptionTests()\n            : base(new CodeCommand().PublisherNameOption, \"-pn\", \"--publisher-name\", ExpectedValue)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/TimestampDigestOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Cli.Test\n{\n    public class TimestampDigestOptionTests : HashAlgorithmNameOptionTests\n    {\n        public TimestampDigestOptionTests()\n            : base(new CodeCommand().TimestampDigestOption, \"-td\", \"--timestamp-digest\")\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Options/TimestampUrlOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public class TimestampUrlOptionTests : UriOptionTests\n    {\n        public TimestampUrlOptionTests()\n            : base(new CodeCommand().TimestampUrlOption, \"-t\", \"--timestamp-url\")\n        {\n        }\n\n        [Fact]\n        public void Option_WhenOptionIsMissing_HasDefaultValue()\n        {\n            ParseResult result = Parse();\n            Uri? value = result.GetValue(Option);\n\n            Assert.NotNull(value);\n            Assert.Equal(\"http://timestamp.acs.microsoft.com/\", value.AbsoluteUri);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/UriOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\n\nnamespace Sign.Cli.Test\n{\n    public abstract class UriOptionTests : OptionTests<Uri?>\n    {\n        private static readonly Uri ExpectedValue = new(\"https://domain.test\");\n\n        protected UriOptionTests(Option<Uri?> option, string shortOption, string longOption)\n            : base(option, shortOption, longOption, ExpectedValue)\n        {\n        }\n\n        [Fact]\n        public void Option_WhenValueFailsToParse_HasError()\n        {\n            const string value = \"3\";\n\n            if (Option.Required)\n            {\n                VerifyHasErrors(\n                    value,\n                    GetOptionRequiredMessage(ShortOption),\n                    GetUnrecognizedCommandOrArgumentMessage(value));\n            }\n            else\n            {\n                VerifyHasErrors(\n                    value,\n                    GetUnrecognizedCommandOrArgumentMessage(value));\n            }\n        }\n\n        [Theory]\n        [InlineData(\"http://domain.test\")]\n        [InlineData(\"https://domain.test\")]\n        public void Option_WithShortOptionAndValidUrl_ParsesValue(string url)\n        {\n            Uri expectedValue = new(url, UriKind.Absolute);\n\n            Verify($\"{ShortOption} {expectedValue.OriginalString}\", expectedValue);\n        }\n\n        [Theory]\n        [InlineData(\"\\\"\\\"\")]\n        [InlineData(\"//domain.test\")]\n        [InlineData(\"/path\")]\n        [InlineData(\"file:///file.bin\")]\n        public void Option_WithShortOptionAndInvalidUrl_HasErrors(string invalidUrl)\n        {\n            VerifyHasErrors(\n                $\"{ShortOption} {invalidUrl}\",\n                GetFormattedResourceString(Resources.InvalidUrlValue, LongOption));\n        }\n\n        protected override void VerifyEqual(Uri? expectedValue, Uri? actualValue)\n        {\n            Assert.NotNull(expectedValue);\n            Assert.NotNull(actualValue);\n            Assert.Equal(expectedValue.IsAbsoluteUri, actualValue.IsAbsoluteUri);\n            Assert.Equal(expectedValue.AbsoluteUri, actualValue.AbsoluteUri);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Options/VerbosityOptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Cli.Test\n{\n    public class VerbosityOptionTests : OptionTests<LogLevel>\n    {\n        private const LogLevel ExpectedValue = LogLevel.Debug;\n\n        public VerbosityOptionTests()\n            : base(new CodeCommand().VerbosityOption, \"-v\", \"--verbosity\", ExpectedValue)\n        {\n        }\n\n        [Theory]\n        [InlineData(LogLevel.Trace)]\n        [InlineData(LogLevel.Debug)]\n        [InlineData(LogLevel.Information)]\n        [InlineData(LogLevel.Warning)]\n        [InlineData(LogLevel.Error)]\n        [InlineData(LogLevel.Critical)]\n        [InlineData(LogLevel.None)]\n        public void Verbosity_WhenValueIsValid_ParsesValue(LogLevel logLevel)\n        {\n            Verify($\"{LongOption} {logLevel}\", logLevel);\n        }\n\n        [Fact]\n        public void Verbosity_WhenValueCasingDoesNotMatchEnumMemberCasing_ParsesValue()\n        {\n            LogLevel logLevel = LogLevel.Warning;\n\n            Verify($\"{LongOption} {logLevel.ToString().ToUpperInvariant()}\", logLevel);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Cli.Test/Sign.Cli.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Moq\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.Cli\\Sign.Cli.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "test/Sign.Cli.Test/SignCommandTests.Globbing.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public partial class SignCommandTests\n    {\n        public sealed class GlobbingTests : IDisposable\n        {\n            private readonly DirectoryService _directoryService;\n            private readonly SignCommand _signCommand;\n            private readonly SignerSpy _signerSpy;\n            private readonly TemporaryDirectory _temporaryDirectory;\n\n            public GlobbingTests()\n            {\n                ServiceCollection services = new();\n\n                _signerSpy = new SignerSpy();\n\n                services.AddSingleton<IMatcherFactory, MatcherFactory>();\n                services.AddSingleton<IFileListReader, FileListReader>();\n                services.AddSingleton<IFileMatcher, FileMatcher>();\n                services.AddSingleton<ISigner>(_signerSpy);\n\n                TestServiceProviderFactory serviceProviderFactory = new(services.BuildServiceProvider());\n\n                _signCommand = Program.CreateCommand(serviceProviderFactory);\n\n                _directoryService = new DirectoryService(Mock.Of<ILogger<IDirectoryService>>());\n                _temporaryDirectory = new TemporaryDirectory(_directoryService);\n\n                CreateFileSystemInfos(\n                    _temporaryDirectory,\n                    \"a.dll\",\n                    \"b.DLL\",\n                    \"c.exe\",\n                    \"d.EXE\",\n                    \"dll\",\n                    \"exe\",\n                    \"e/f.dll\",\n                    \"e/g.DLL\",\n                    \"e/h.exe\",\n                    \"e/i.EXE\");\n            }\n\n            public void Dispose()\n            {\n                _temporaryDirectory.Dispose();\n                _directoryService.Dispose();\n\n                GC.SuppressFinalize(this);\n            }\n\n            [Fact]\n            public async Task Command_WhenFileIsGlobPattern_SignsOnlyMatches()\n            {\n                string commandText = $\"code --description {Description} --description-url {DescriptionUrl} --timestamp-url {TimestampUrl} \"\n                    + $\"-b \\\"{_temporaryDirectory.Directory.FullName}\\\" azure-key-vault -kvu {KeyVaultUrl} -kvc {CertificateName} **/*.dll\";\n\n                int exitCode = await _signCommand.Parse(commandText).InvokeAsync();\n\n                Assert.Equal(_signerSpy.ExitCode, exitCode);\n                Assert.NotNull(_signerSpy.InputFiles);\n                Assert.Collection(_signerSpy.InputFiles,\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"a.dll\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"b.DLL\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\f.dll\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\g.DLL\"));\n            }\n\n            [Fact]\n            public async Task Command_WhenFileIsGlobPatternWithSubdirectory_SignsOnlyMatches()\n            {\n                string commandText = $\"code --description {Description} --description-url {DescriptionUrl} --timestamp-url {TimestampUrl} \"\n                    + $\"-b \\\"{_temporaryDirectory.Directory.FullName}\\\" azure-key-vault -kvu {KeyVaultUrl} -kvc {CertificateName} **/e/*.dll\";\n\n                int exitCode = await _signCommand.Parse(commandText).InvokeAsync();\n\n                Assert.Equal(_signerSpy.ExitCode, exitCode);\n                Assert.NotNull(_signerSpy.InputFiles);\n                Assert.Collection(_signerSpy.InputFiles,\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\f.dll\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\g.DLL\"));\n            }\n\n            [Fact]\n            public async Task Command_WhenFileIsGlobPatternWithBracedExpansion_SignsOnlyMatches()\n            {\n                string commandText = $\"code --description {Description} --description-url {DescriptionUrl} --timestamp-url {TimestampUrl} \"\n                      + $\"-b \\\"{_temporaryDirectory.Directory.FullName}\\\" azure-key-vault -kvu {KeyVaultUrl} -kvc {CertificateName} **/*.{{dll,exe}}\";\n\n                int exitCode = await _signCommand.Parse(commandText).InvokeAsync();\n\n                Assert.Equal(_signerSpy.ExitCode, exitCode);\n                Assert.NotNull(_signerSpy.InputFiles);\n                Assert.Collection(_signerSpy.InputFiles,\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"a.dll\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"b.DLL\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"c.exe\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, \"d.EXE\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\f.dll\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\g.DLL\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\h.exe\"),\n                    inputFile => AssertIsExpectedInputFile(inputFile, _temporaryDirectory, @\"e\\i.EXE\"));\n            }\n\n            private static void AssertIsExpectedInputFile(FileInfo inputFile, TemporaryDirectory temporaryDirectory, string relativePath)\n            {\n                string expectedFilePath = Path.Combine(temporaryDirectory.Directory.FullName, relativePath);\n                string actualFilePath = inputFile.FullName;\n\n                Assert.Equal(expectedFilePath, actualFilePath);\n            }\n\n            private static void CreateFileSystemInfos(TemporaryDirectory directory, params string[] paths)\n            {\n                foreach (string path in paths)\n                {\n                    bool isDirectory = path.EndsWith('/');\n                    string relativePath = path.TrimEnd('/').Replace('/', '\\\\');\n                    string fullPath = Path.Combine(directory.Directory.FullName, relativePath);\n\n                    if (isDirectory)\n                    {\n                        CreateSubdirectory(fullPath);\n                    }\n                    else\n                    {\n                        CreateFile(fullPath);\n                    }\n                }\n            }\n\n            private static void CreateSubdirectory(string fullPath)\n            {\n                DirectoryInfo subdirectory = new(fullPath);\n\n                EnsureParentDirectoriesExist(subdirectory.Parent!);\n\n                subdirectory.Create();\n            }\n\n            private static void CreateFile(string fullPath)\n            {\n                FileInfo file = new(fullPath);\n\n                EnsureParentDirectoriesExist(file.Directory!);\n\n                System.IO.File.WriteAllText(file.FullName, string.Empty);\n            }\n\n            private static void EnsureParentDirectoriesExist(DirectoryInfo directory)\n            {\n                Stack<DirectoryInfo> directoriesToCreate = new();\n                DirectoryInfo? parent = directory;\n\n                while (parent is not null)\n                {\n                    if (parent.Exists)\n                    {\n                        break;\n                    }\n\n                    directoriesToCreate.Push(parent);\n\n                    parent = parent.Parent;\n                }\n\n                while (directoriesToCreate.TryPop(out DirectoryInfo? directoryToCreate))\n                {\n                    directoryToCreate.Create();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/SignCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing System.CommandLine.Parsing;\n\nnamespace Sign.Cli.Test\n{\n    public partial class SignCommandTests\n    {\n        private const string Description = \"a\";\n        private const string DescriptionUrl = \"https://description.test\";\n        private const string KeyVaultUrl = \"https://keyvault.test\";\n        private const string CertificateName = \"b\";\n        private const string TimestampUrl = \"http://timestamp.test\";\n        private const string File = \"c\";\n\n        private readonly SignCommand _signCommand;\n        private readonly CodeCommand _codeCommand;\n        private readonly AzureKeyVaultCommand _azureKeyVaultCommand;\n\n        public SignCommandTests()\n        {\n            _signCommand = Program.CreateCommand();\n\n            Assert.NotNull(_signCommand);\n\n            CodeCommand? codeCommand = _signCommand.Subcommands\n                .Where(child => child is CodeCommand)\n                .Single() as CodeCommand;\n\n            Assert.NotNull(codeCommand);\n\n            AzureKeyVaultCommand? azureKeyVaultCommand = codeCommand.Subcommands\n                .Where(child => child is AzureKeyVaultCommand)\n                .Single() as AzureKeyVaultCommand;\n\n            Assert.NotNull(azureKeyVaultCommand);\n\n            _codeCommand = codeCommand;\n            _azureKeyVaultCommand = azureKeyVaultCommand;\n        }\n\n        [Fact]\n        public void Help_Always_IsEnabled()\n        {\n            ParseResult result = _signCommand.Parse(\"-?\");\n            SymbolResult symbolResult = result.CommandResult.Children.Single();\n            OptionResult? optionResult = symbolResult as OptionResult;\n\n            Assert.NotNull(optionResult);\n\n            string[] expectedAliases = new[] { \"-?\", \"-h\", \"/?\", \"/h\" };\n            string[] actualAliases = optionResult.Option.Aliases.OrderBy(_ => _, StringComparer.Ordinal).ToArray();\n\n            Assert.Equal(expectedAliases, actualAliases);\n            Assert.Empty(result.Errors);\n        }\n\n        [Theory]\n        [InlineData(\"code\")]\n        [InlineData(\"code azure-key-vault\")]\n        public void Command_WhenArgumentAndOptionsAreMissing_HasError(string command)\n        {\n            ParseResult result = _signCommand.Parse(command);\n            Assert.NotEmpty(result.Errors);\n        }\n\n        [Fact]\n        public void Command_WhenRequiredArgumentIsMissing_HasError()\n        {\n            string command = $\"code --description {Description} --description-url {DescriptionUrl} --timestamp-url {TimestampUrl} \"\n                + $\"azure-key-vault -kvu {KeyVaultUrl} -kvc {CertificateName}\";\n            ParseResult result = _signCommand.Parse(command);\n\n            Assert.NotEmpty(result.Errors);\n        }\n\n        [Fact]\n        public void Command_WhenAllOptionsAndArgumentAreValid_HasNoError()\n        {\n            string command = $\"code --description {Description} --description-url {DescriptionUrl} --timestamp-url {TimestampUrl} \"\n                + $\"azure-key-vault -kvu {KeyVaultUrl} -kvc {CertificateName} {File}\";\n            ParseResult result = _signCommand.Parse(command);\n\n            Assert.Empty(result.Errors);\n\n            Assert.Equal(Description, result.GetValue(_codeCommand.DescriptionOption));\n            Assert.Equal(DescriptionUrl, result.GetValue(_codeCommand.DescriptionUrlOption)!.OriginalString);\n            Assert.Equal(KeyVaultUrl, result.GetValue(_azureKeyVaultCommand.UrlOption)!.OriginalString);\n            Assert.Equal(CertificateName, result.GetValue(_azureKeyVaultCommand.CertificateOption));\n            Assert.Equal(TimestampUrl, result.GetValue(_codeCommand.TimestampUrlOption)!.OriginalString);\n            Assert.Equal([File], result.GetValue(_azureKeyVaultCommand.FilesArgument));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/TemporaryConsoleEncodingTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Text;\n\nnamespace Sign.Cli.Test\n{\n    public class TemporaryConsoleEncodingTests : IDisposable\n    {\n        private readonly Encoding _defaultInputEncoding;\n        private readonly Encoding _defaultOutputEncoding;\n\n        public TemporaryConsoleEncodingTests()\n        {\n            _defaultInputEncoding = Console.InputEncoding;\n            _defaultOutputEncoding = Console.OutputEncoding;\n\n            Console.InputEncoding = Encoding.UTF8;\n            Console.OutputEncoding = Encoding.UTF8;\n        }\n\n        public void Dispose()\n        {\n            Console.InputEncoding = _defaultInputEncoding;\n            Console.OutputEncoding = _defaultOutputEncoding;\n\n            GC.SuppressFinalize(this);\n        }\n\n        [Fact]\n        public void Constructor_Always_SetsUtf8Encoding()\n        {\n            Console.InputEncoding = Encoding.ASCII;\n            Console.OutputEncoding = Encoding.ASCII;\n\n            using (new TemporaryConsoleEncoding())\n            {\n                Assert.Equal(Encoding.UTF8, Console.InputEncoding);\n                Assert.Equal(Encoding.UTF8, Console.OutputEncoding);\n            }\n        }\n\n        [Fact]\n        public void Dispose_Always_RevertsEncoding()\n        {\n            Console.InputEncoding = Encoding.ASCII;\n            Console.OutputEncoding = Encoding.ASCII;\n\n            using (new TemporaryConsoleEncoding())\n            {\n            }\n\n            Assert.Equal(Encoding.ASCII, Console.InputEncoding);\n            Assert.Equal(Encoding.ASCII, Console.OutputEncoding);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/TestInfrastructure/SignerSpy.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    internal sealed class SignerSpy : ISigner\n    {\n        internal IReadOnlyList<FileInfo>? InputFiles { get; private set; }\n        internal string? OutputFile { get; private set; }\n        internal FileInfo? FileList { get; private set; }\n        internal DirectoryInfo? BaseDirectory { get; private set; }\n        internal bool RecurseContainers { get; private set; }\n        internal string? ApplicationName { get; private set; }\n        internal string? PublisherName { get; private set; }\n        internal string? Description { get; private set; }\n        internal Uri? DescriptionUrl { get; private set; }\n        internal Uri? TimestampUrl { get; private set; }\n        internal int? MaxConcurrency { get; private set; }\n        internal HashAlgorithmName? FileHashAlgorithm { get; private set; }\n        internal HashAlgorithmName? TimestampHashAlgorithm { get; private set; }\n        internal int ExitCode { get; }\n\n        internal SignerSpy()\n        {\n            ExitCode = Core.ExitCode.Success;\n        }\n\n        public Task<int> SignAsync(\n            IReadOnlyList<FileInfo> inputFiles,\n            string? outputFile,\n            FileInfo? fileList,\n            bool recurseContainers,\n            DirectoryInfo baseDirectory,\n            string? applicationName,\n            string? publisherName,\n            string? description,\n            Uri? descriptionUrl,\n            Uri timestampUrl,\n            int maxConcurrency,\n            HashAlgorithmName fileHashAlgorithm,\n            HashAlgorithmName timestampHashAlgorithm)\n        {\n            InputFiles = inputFiles;\n            OutputFile = outputFile;\n            FileList = fileList;\n            RecurseContainers = recurseContainers;\n            BaseDirectory = baseDirectory;\n            ApplicationName = applicationName;\n            PublisherName = publisherName;\n            Description = description;\n            DescriptionUrl = descriptionUrl;\n            TimestampUrl = timestampUrl;\n            MaxConcurrency = maxConcurrency;\n            FileHashAlgorithm = fileHashAlgorithm;\n            TimestampHashAlgorithm = timestampHashAlgorithm;\n\n            return Task.FromResult(ExitCode);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/TestInfrastructure/TestServiceProviderFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    internal sealed class TestServiceProviderFactory : IServiceProviderFactory\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        internal TestServiceProviderFactory(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        public IServiceProvider Create(\n            LogLevel logLevel = LogLevel.Information,\n            ILoggerProvider? loggerProvider = null,\n            Action<IServiceCollection>? addServices = null)\n        {\n            return _serviceProvider;\n        }\n\n        public void AddServices(Action<IServiceCollection> addServices)\n        { }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/TrustedSigningCommandTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.CommandLine;\nusing Moq;\nusing Sign.Core;\n\nnamespace Sign.Cli.Test\n{\n    public class TrustedSigningCommandTests\n    {\n        private readonly TrustedSigningCommand _command = new(new CodeCommand(), Mock.Of<IServiceProviderFactory>());\n\n        [Fact]\n        public void Constructor_WhenCodeCommandIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new TrustedSigningCommand(codeCommand: null!, Mock.Of<IServiceProviderFactory>()));\n\n            Assert.Equal(\"codeCommand\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderFactoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new TrustedSigningCommand(new CodeCommand(), serviceProviderFactory: null!));\n\n            Assert.Equal(\"serviceProviderFactory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void EndpointOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.EndpointOption.Arity);\n        }\n\n        [Fact]\n        public void EndpointOption_Always_IsRequired()\n        {\n            Assert.True(_command.EndpointOption.Required);\n        }\n\n        [Fact]\n        public void AccountOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.AccountOption.Arity);\n        }\n\n        [Fact]\n        public void AccountOption_Always_IsRequired()\n        {\n            Assert.True(_command.AccountOption.Required);\n        }\n\n        [Fact]\n        public void CertificateProfileOption_Always_HasArityOfExactlyOne()\n        {\n            Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateProfileOption.Arity);\n        }\n\n        [Fact]\n        public void CertificateProfileOption_Always_IsRequired()\n        {\n            Assert.True(_command.CertificateProfileOption.Required);\n        }\n\n        [Fact]\n        public void Command_Description_IndicatesObsolete()\n        {\n            Assert.Contains(\"obsolete\", _command.Description, StringComparison.OrdinalIgnoreCase);\n        }\n\n        public class ParserTests\n        {\n            private readonly TrustedSigningCommand _command;\n            private readonly RootCommand _rootCommand;\n\n            public ParserTests()\n            {\n                CodeCommand codeCommand = new();\n                _command = new(codeCommand, Mock.Of<IServiceProviderFactory>());\n                _rootCommand = new RootCommand();\n                _rootCommand.Subcommands.Add(codeCommand);\n                codeCommand.Subcommands.Add(_command);\n            }\n\n            [Theory]\n            [InlineData(\"code trusted-signing\")]\n            [InlineData(\"code trusted-signing a\")]\n            [InlineData(\"code trusted-signing -tse\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c -kvi\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c -kvi d\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c -kvi d -kvs\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c -kvi d -kvs e\")]\n            public void Command_WhenRequiredArgumentOrOptionsAreMissing_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b -kvt c -kvi d -kvs e f\")]\n            public void Command_WhenRequiredArgumentsArePresent_HasNoError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n            }\n\n            [Theory]\n            [InlineData(\"code trusted-signing -tse \\\"\\\" -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse //trustedsigning.test -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse /path -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse file:///file.bin -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse http://trustedsigning.test -tsa a -tscp b c\")]\n            [InlineData(\"code trusted-signing -tse ftp://trustedsigning.test -tsa a -tscp b c\")]\n            public void Command_WhenEndpointUrlIsInvalid_HasError(string command)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.NotEmpty(result.Errors);\n                Assert.Contains(result.Errors, error => error.Message.Contains(\"URL\"));\n            }\n\n            [Theory]\n            [InlineData(\"code trusted-signing -tse https://trustedsigning.test -tsa a -tscp b c\", \"https://trustedsigning.test/\")]\n            [InlineData(\"code trusted-signing -tse HTTPS://TRUSTEDSIGNING.TEST -tsa a -tscp b c\", \"https://trustedsigning.test/\")]\n            public void Command_WhenEndpointUrlIsValidHttps_ParsesCorrectly(string command, string expectedUrl)\n            {\n                ParseResult result = _rootCommand.Parse(command);\n\n                Assert.Empty(result.Errors);\n                Uri? actualUrl = result.GetValue(_command.EndpointOption);\n                Assert.NotNull(actualUrl);\n                Assert.Equal(expectedUrl, actualUrl.AbsoluteUri);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Cli.Test/Usings.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nglobal using Xunit;"
  },
  {
    "path": "test/Sign.Core.Test/AssemblyInitializer.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Runtime.CompilerServices;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public sealed class AssemblyInitializer\n    {\n        [ModuleInitializer]\n        public static void Initialize()\n        {\n            AppInitializer.Initialize();\n\n            EphemeralTrust.RemoveResidualTestCertificates();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Certificates/CertificateVerifierTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public class CertificateVerifierTests\n    {\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateVerifier(logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Verify_WhenCertificateIsNull_Throws()\n        {\n            CertificateVerifier verifier = new(Mock.Of<ILogger<ICertificateVerifier>>());\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => verifier.Verify(certificate: null!));\n\n            Assert.Equal(\"certificate\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Verify_WhenCertificateIsNotYetTimeValid_Throws()\n        {\n            Logger logger = new(Resources.CertificateIsNotYetTimeValid);\n            CertificateVerifier verifier = new(logger);\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate(\n                notBefore: now.AddDays(1),\n                notAfter: now.AddDays(2)))\n            {\n                Assert.Throws<SigningException>(() => verifier.Verify(certificate));\n            }\n\n            Assert.Equal(1, logger.Log_CallCount);\n        }\n\n        [Fact]\n        public void Verify_WhenCertificateIsExpired_Throws()\n        {\n            Logger logger = new(Resources.CertificateIsExpired);\n            CertificateVerifier verifier = new(logger);\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate(\n                notBefore: now.AddDays(-2),\n                notAfter: now.AddDays(-1)))\n            {\n                Assert.Throws<SigningException>(() => verifier.Verify(certificate));\n            }\n\n            Assert.Equal(1, logger.Log_CallCount);\n        }\n\n        [Fact]\n        public void Verify_WhenCertificateIsTimeValid_DoesNotLogWarning()\n        {\n            Logger logger = new();\n            CertificateVerifier verifier = new(logger);\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate(\n                notBefore: now.AddDays(-1),\n                notAfter: now.AddDays(1)))\n            {\n                verifier.Verify(certificate);\n            }\n\n            Assert.Equal(0, logger.Log_CallCount);\n        }\n\n        private sealed class Logger : ILogger<ICertificateVerifier>\n        {\n            private readonly string? _expectedMessage;\n\n            internal int Log_CallCount { get; private set; }\n\n            internal Logger(string? expectedMessage = null)\n            {\n                _expectedMessage = expectedMessage;\n            }\n\n            public IDisposable? BeginScope<TState>(TState state) where TState : notnull\n            {\n                return new NoOpDisposable();\n            }\n\n            public bool IsEnabled(LogLevel logLevel)\n            {\n                return true;\n            }\n\n            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)\n            {\n                ++Log_CallCount;\n\n                Assert.Equal(LogLevel.Error, logLevel);\n\n                string actualMessage = formatter(state, exception);\n\n                Assert.Equal(_expectedMessage, actualMessage);\n            }\n\n            private sealed class NoOpDisposable : IDisposable\n            {\n                public void Dispose()\n                {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Containers/AppxBundleContainerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class AppxBundleContainerTests\n    {\n        [Fact]\n        public void Constructor_WhenAppxIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxBundleContainer(\n                    appxBundle: null!,\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"appxBundle\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDirectoryServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxBundleContainer(\n                    new FileInfo(\"a\"),\n                    directoryService: null!,\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxBundleContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    fileMatcher: null!,\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenMakeAppxCliIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxBundleContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    makeAppxCli: null!,\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"makeAppxCli\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxBundleContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Containers/AppxContainerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class AppxContainerTests\n    {\n        [Fact]\n        public void Constructor_WhenAppxIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: null!,\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainer>>()));\n\n            Assert.Equal(\"appx\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: new FileInfo(\"a\"),\n                    certificateProvider: null!,\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainer>>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDirectoryServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: new FileInfo(\"a\"),\n                    Mock.Of<ICertificateProvider>(),\n                    directoryService: null!,\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainer>>()));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: new FileInfo(\"a\"),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    fileMatcher: null!,\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainer>>()));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenMakeAppxCliIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: new FileInfo(\"a\"),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    makeAppxCli: null!,\n                    Mock.Of<ILogger<IContainer>>()));\n\n            Assert.Equal(\"makeAppxCli\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppxContainer(\n                    appx: new FileInfo(\"a\"),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Containers/ContainerProviderTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class ContainerProviderTests\n    {\n        private readonly ContainerProvider _provider;\n\n        public ContainerProviderTests()\n        {\n            _provider = new ContainerProvider(\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<IDirectoryService>(),\n                Mock.Of<IFileMatcher>(),\n                Mock.Of<IMakeAppxCli>(),\n                Mock.Of<ILogger<IContainerProvider>>());\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ContainerProvider(\n                    certificateProvider: null!,\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainerProvider>>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDirectoryServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ContainerProvider(\n                    Mock.Of<ICertificateProvider>(),\n                    directoryService: null!,\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainerProvider>>()));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ContainerProvider(\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    fileMatcher: null!,\n                    Mock.Of<IMakeAppxCli>(),\n                    Mock.Of<ILogger<IContainerProvider>>()));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenMakeAppxCliIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ContainerProvider(\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    makeAppxCli: null!,\n                    Mock.Of<ILogger<IContainerProvider>>()));\n\n            Assert.Equal(\"makeAppxCli\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ContainerProvider(\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<IMakeAppxCli>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void IsAppxBundleContainer_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.IsAppxBundleContainer(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".dll\")]\n        [InlineData(\".msİxbundle\")] // Turkish İ (U+0130)\n        [InlineData(\".msıxbundle\")] // Turkish ı (U+0131)\n        public void IsAppxBundleContainer_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_provider.IsAppxBundleContainer(file));\n        }\n\n        [Theory]\n        [InlineData(\".appxbundle\")]\n        [InlineData(\".eappxbundle\")]\n        [InlineData(\".emsixbundle\")]\n        [InlineData(\".msixbundle\")]\n        [InlineData(\".MSIXBUNDLE\")] // test case insensitivity\n        public void IsAppxBundleContainer_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_provider.IsAppxBundleContainer(file));\n        }\n\n        [Fact]\n        public void IsAppxContainer_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.IsAppxContainer(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".dll\")]\n        [InlineData(\".msİx\")] // Turkish İ (U+0130)\n        [InlineData(\".msıx\")] // Turkish ı (U+0131)\n        public void IsAppxContainer_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_provider.IsAppxContainer(file));\n        }\n\n        [Theory]\n        [InlineData(\".appx\")]\n        [InlineData(\".eappx\")]\n        [InlineData(\".emsix\")]\n        [InlineData(\".msix\")]\n        [InlineData(\".MSIX\")] // test case insensitivity\n        public void IsAppxContainer_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_provider.IsAppxContainer(file));\n        }\n\n        [Fact]\n        public void IsNuGetContainer_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.IsNuGetContainer(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".zip\")]\n        public void IsNuGetContainer_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_provider.IsNuGetContainer(file));\n        }\n\n        [Theory]\n        [InlineData(\".nupkg\")]\n        [InlineData(\".snupkg\")]\n        [InlineData(\".NuPkg\")] // test case insensitivity\n        public void IsNuGetContainer_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_provider.IsNuGetContainer(file));\n        }\n\n        [Fact]\n        public void IsZipContainer_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.IsZipContainer(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".dll\")]\n        [InlineData(\".msİx\")] // Turkish İ (U+0130)\n        [InlineData(\".msıx\")] // Turkish ı (U+0131)\n        public void IsZipContainer_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_provider.IsZipContainer(file));\n        }\n\n        [Theory]\n        [InlineData(\".appxupload\")]\n        [InlineData(\".clickonce\")]\n        [InlineData(\".msixupload\")]\n        [InlineData(\".vsix\")]\n        [InlineData(\".zip\")]\n        [InlineData(\".ZIP\")] // test case insensitivity\n        public void IsZipContainer_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_provider.IsZipContainer(file));\n        }\n\n        [Fact]\n        public void GetContainer_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.GetContainer(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetContainer_WhenFileExtensionDoesNotMatch_ReturnsFalse()\n        {\n            FileInfo file = new(\"file.dll\");\n\n            Assert.Null(_provider.GetContainer(file));\n        }\n\n        [Fact]\n        public void GetContainer_WhenFileExtensionMatchesZip_ReturnsContainer()\n        {\n            FileInfo file = new(\"file.zip\");\n            IContainer? container = _provider.GetContainer(file);\n\n            Assert.IsType<ZipContainer>(container);\n        }\n\n        [Fact]\n        public void GetContainer_WhenFileExtensionMatchesAppx_ReturnsContainer()\n        {\n            FileInfo file = new(\"file.appx\");\n            IContainer? container = _provider.GetContainer(file);\n\n            Assert.IsType<AppxContainer>(container);\n        }\n\n        [Fact]\n        public void GetContainer_WhenFileExtensionMatchesAppxBundle_ReturnsContainer()\n        {\n            FileInfo file = new(\"file.appxbundle\");\n            IContainer? container = _provider.GetContainer(file);\n\n            Assert.IsType<AppxBundleContainer>(container);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Containers/NuGetContainerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing NuGet.Packaging.Signing;\n\nnamespace Sign.Core.Test\n{\n    public class NuGetContainerTests\n    {\n        [Fact]\n        public void Constructor_WhenZipFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetContainer(\n                    zipFile: null!,\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"zipFile\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDirectoryServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetContainer(\n                    new FileInfo(\"a\"),\n                    directoryService: null!,\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    fileMatcher: null!,\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task Dispose_WhenOpened_RemovesTemporaryDirectory()\n        {\n            string[] expectedFileNames = new[] { \"a\" };\n            FileInfo zipFile = CreateZipFile(expectedFileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            {\n                DirectoryInfo? directory;\n\n                using (NuGetContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n                {\n                    await container.OpenAsync();\n\n                    directory = Assert.Single(directoryService.Directories);\n\n                    Assert.True(directory.Exists);\n                }\n\n                directory = Assert.Single(directoryService.Directories);\n\n                Assert.False(directory.Exists);\n            }\n        }\n\n        [Fact]\n        public async Task OpenAsync_WhenNupkgFileIsNonEmpty_ExtractsNupkgToDirectory()\n        {\n            string[] expectedFileNames = new[] { \".a\", \"b\", \"c.d\" };\n            FileInfo zipFile = CreateZipFile(expectedFileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            using (NuGetContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n            {\n                await container.OpenAsync();\n\n                FileInfo[] actualFiles = directoryService.Directories[0].GetFiles(\"*\", SearchOption.AllDirectories);\n                string[] actualFileNames = actualFiles\n                    .Select(file => file.FullName.Substring(directoryService.Directories[0].FullName.Length + 1))\n                    .ToArray();\n\n                Assert.Equal(expectedFileNames, actualFileNames);\n            }\n        }\n\n        [Fact]\n        public async Task SaveAsync_WhenNupkgFileIsNonEmpty_CompressesNupkgFromDirectory()\n        {\n            string[] fileNames = new[] { \"a\" };\n            FileInfo zipFile = CreateZipFile(fileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            using (NuGetContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n            {\n                await container.OpenAsync();\n\n                File.WriteAllText(Path.Combine(directoryService.Directories[0].FullName, \"b\"), \"b\");\n\n                await container.SaveAsync();\n            }\n\n            using (FileStream stream = zipFile.OpenRead())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Read))\n            {\n                Assert.Equal(2, zip.Entries.Count);\n                Assert.NotNull(zip.GetEntry(\"a\"));\n                Assert.NotNull(zip.GetEntry(\"b\"));\n            }\n        }\n\n        [Fact]\n        public async Task SaveAsync_WhenNupkgFileHasSignatureFile_RemovesSignatureFile()\n        {\n            string[] fileNames = new[] { \"a\", SigningSpecifications.V1.SignaturePath };\n            FileInfo zipFile = CreateZipFile(fileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            using (NuGetContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n            {\n                await container.OpenAsync();\n                await container.SaveAsync();\n            }\n\n            using (FileStream stream = zipFile.OpenRead())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Read))\n            {\n                ZipArchiveEntry entry = Assert.Single(zip.Entries);\n                Assert.Equal(fileNames[0], entry.Name);\n            }\n        }\n\n        private static FileInfo CreateZipFile(params string[] entryNames)\n        {\n            FileInfo file = new(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n\n            using (FileStream stream = file.OpenWrite())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Create))\n            {\n                foreach (string entryName in entryNames)\n                {\n                    ZipArchiveEntry entry = zip.CreateEntry(entryName);\n\n                    using (Stream entryStream = entry.Open())\n                    {\n                        byte[] bytes = Encoding.UTF8.GetBytes(entryName);\n\n                        entryStream.Write(bytes);\n                    }\n                }\n            }\n\n            return file;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Containers/ZipContainerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class ZipContainerTests\n    {\n        [Fact]\n        public void Constructor_WhenZipFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ZipContainer(\n                    zipFile: null!,\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"zipFile\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDirectoryServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ZipContainer(\n                    new FileInfo(\"a\"),\n                    directoryService: null!,\n                    Mock.Of<IFileMatcher>(),\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ZipContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    fileMatcher: null!,\n                    Mock.Of<ILogger>()));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ZipContainer(\n                    new FileInfo(\"a\"),\n                    Mock.Of<IDirectoryService>(),\n                    Mock.Of<IFileMatcher>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task Dispose_WhenOpened_RemovesTemporaryDirectory()\n        {\n            string[] expectedFileNames = new[] { \"a\" };\n            FileInfo zipFile = CreateZipFile(expectedFileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            {\n                DirectoryInfo? directory;\n\n                using (ZipContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n                {\n                    await container.OpenAsync();\n\n                    directory = Assert.Single(directoryService.Directories);\n\n                    Assert.True(directory.Exists);\n                }\n\n                directory = Assert.Single(directoryService.Directories);\n\n                Assert.False(directory.Exists);\n            }\n        }\n\n        [Fact]\n        public async Task OpenAsync_WhenZipFileIsNonEmpty_ExtractsZipToDirectory()\n        {\n            string[] expectedFileNames = new[] { \".a\", \"b\", \"c.d\" };\n            FileInfo zipFile = CreateZipFile(expectedFileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            using (ZipContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n            {\n                await container.OpenAsync();\n\n                FileInfo[] actualFiles = directoryService.Directories[0].GetFiles(\"*\", SearchOption.AllDirectories);\n                string[] actualFileNames = actualFiles\n                    .Select(file => file.FullName.Substring(directoryService.Directories[0].FullName.Length + 1))\n                    .ToArray();\n\n                Assert.Equal(expectedFileNames, actualFileNames);\n            }\n        }\n\n        [Fact]\n        public async Task SaveAsync_WhenZipFileIsNonEmpty_CompressesZipFromDirectory()\n        {\n            string[] fileNames = new[] { \"a\" };\n            FileInfo zipFile = CreateZipFile(fileNames);\n\n            using (DirectoryServiceStub directoryService = new())\n            using (ZipContainer container = new(zipFile, directoryService, Mock.Of<IFileMatcher>(), Mock.Of<ILogger>()))\n            {\n                await container.OpenAsync();\n\n                File.WriteAllText(Path.Combine(directoryService.Directories[0].FullName, \"b\"), \"b\");\n\n                await container.SaveAsync();\n            }\n\n            using (FileStream stream = zipFile.OpenRead())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Read))\n            {\n                Assert.Equal(2, zip.Entries.Count);\n                Assert.NotNull(zip.GetEntry(\"a\"));\n                Assert.NotNull(zip.GetEntry(\"b\"));\n            }\n        }\n\n        private static FileInfo CreateZipFile(params string[] entryNames)\n        {\n            FileInfo file = new(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n\n            using (FileStream stream = file.OpenWrite())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Create))\n            {\n                foreach (string entryName in entryNames)\n                {\n                    ZipArchiveEntry entry = zip.CreateEntry(entryName);\n\n                    using (Stream entryStream = entry.Open())\n                    {\n                        byte[] bytes = Encoding.UTF8.GetBytes(entryName);\n\n                        entryStream.Write(bytes);\n                    }\n                }\n            }\n\n            return file;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/AggregatingSignerTests.Containers.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Text;\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core.Test\n{\n    public partial class AggregatingSignerTests\n    {\n        private const string AppxBundleContainerName = \"container.appxbundle\";\n        private const string AppxContainerName = \"container.appx\";\n        private const string ZipContainerName = \"container.zip\";\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsEmptyAppxBundleContainer_SignsNothing()\n        {\n            AggregatingSignerTest test = new(AppxBundleContainerName);\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[AppxBundleContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(1, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(0, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(AppxBundleContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsAppxBundleContainer_SignsNestedAppxAndMsixFiles()\n        {\n            AggregatingSignerTest test = new(\n                $\"{AppxBundleContainerName}/nestedcontainer.appx/a.dll\",\n                $\"{AppxBundleContainerName}/nestedcontainer.msix/b.dll\");\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[AppxBundleContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(1, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.appx\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.msix\", signedFile.Name),\n                signedFile => Assert.Equal(AppxBundleContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenRecurseContainersIsFalse_SignsOnlyAppxItself()\n        {\n            AggregatingSignerTest test = new(\n                $\"{AppxBundleContainerName}/nestedcontainer.appx/a.dll\",\n                $\"{AppxBundleContainerName}/nestedcontainer.msix/b.dll\");\n\n            SignOptions options = new(\n                applicationName: null,\n                publisherName: null,\n                description: null,\n                descriptionUrl: new Uri(\"https://description.test\"),\n                fileHashAlgorithm: HashAlgorithmName.SHA256,\n                timestampHashAlgorithm: HashAlgorithmName.SHA256,\n                timestampService: new Uri(\"https://timestamp.test\"),\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: false);\n\n            await test.Signer.SignAsync(test.Files, options);\n\n            ContainerSpy container = test.Containers[AppxBundleContainerName];\n\n            Assert.Equal(0, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(0, container.SaveAsync_CallCount);\n            Assert.Equal(0, container.Dispose_CallCount);\n\n            // The only file should be the appx bundle container itself, since we did not recurse into it\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(AppxBundleContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsAppxBundleContainerAndGlobAndAntiGlobPatternsAreUsed_SignsOnlyMatchingFiles()\n        {\n            const string fileListContents =\n@\"**/*.dll\n**/*.exe\n!**/*.txt\n!**/DoNotSign/**/*\";\n            ReadFileList(fileListContents, out Matcher matcher, out Matcher antiMatcher);\n\n            SignOptions options = new(\n                applicationName: \"a\",\n                publisherName: \"b\",\n                description: \"c\",\n                new Uri(\"https://description.test\"),\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                new Uri(\"https://timestamp.test\"),\n                matcher,\n                antiMatcher,\n                recurseContainers: true);\n\n            AggregatingSignerTest test = new(\n                $\"{AppxBundleContainerName}/a.dll\",\n                $\"{AppxBundleContainerName}/b.DLL\",\n                $\"{AppxBundleContainerName}/c.txt\",\n                $\"{AppxBundleContainerName}/d.exe\",\n                $\"{AppxBundleContainerName}/e.EXE\",\n                $\"{AppxBundleContainerName}/f/g.dll\",\n                $\"{AppxBundleContainerName}/f/h.txt\",\n                $\"{AppxBundleContainerName}/f/i.exe\",\n                $\"{AppxBundleContainerName}/DoNotSign/j.dll\",\n                $\"{AppxBundleContainerName}/DoNotSign/k.txt\",\n                $\"{AppxBundleContainerName}/DoNotSign/l/m.txt\",\n                $\"{AppxBundleContainerName}/DoNotSign/l/n.exe\");\n\n            await test.Signer.SignAsync(test.Files, options);\n\n            ContainerSpy container = test.Containers[AppxBundleContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(1, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(0, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(AppxBundleContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsEmptyAppxContainer_SignsNothing()\n        {\n            AggregatingSignerTest test = new(AppxContainerName);\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[AppxContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(1, container.GetFiles_CallCount);\n            Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(AppxContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsAppxContainer_SignsPortableExecutableFiles()\n        {\n            AggregatingSignerTest test = new(\n                $\"{AppxContainerName}/a.dll\",\n                $\"{AppxContainerName}/b.exe\",\n                $\"{AppxContainerName}/c/d.dll\");\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[AppxContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(1, container.GetFiles_CallCount);\n            Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.exe\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.dll\", signedFile.Name),\n                signedFile => Assert.Equal(AppxContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsAppxContainerWithNestedContentAndContainers_SignsContentInsideOut()\n        {\n            AggregatingSignerTest test = new(\n                $\"{AppxContainerName}/a.dll\",\n                $\"{AppxContainerName}/nestedcontainer0.zip/b.dll\",\n                $\"{AppxContainerName}/nestedcontainer0.zip/nestedcontainer1.zip/c.dll\",\n                $\"{AppxContainerName}/d.appinstaller\",\n                $\"{AppxContainerName}/nestedcontainer.nupkg/folder0/folder1/f.dll\",\n                $\"{AppxContainerName}/nestedcontainer.vsix/folder0/folder1/folder2/g.dll\");\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            foreach (string containerName in new[]\n            {\n                AppxContainerName,\n                $\"{AppxContainerName}/nestedcontainer0.zip\",\n                $\"{AppxContainerName}/nestedcontainer0.zip/nestedcontainer1.zip\",\n                $\"{AppxContainerName}/nestedcontainer.nupkg\",\n                $\"{AppxContainerName}/nestedcontainer.vsix\"\n            })\n            {\n                ContainerSpy container = test.Containers[containerName];\n\n                Assert.Equal(1, container.OpenAsync_CallCount);\n                Assert.Equal(1, container.GetFiles_CallCount);\n                Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n                Assert.Equal(1, container.SaveAsync_CallCount);\n                Assert.Equal(1, container.Dispose_CallCount);\n            }\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"c.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"f.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"g.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.appinstaller\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.nupkg\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.vsix\", signedFile.Name),\n                signedFile => Assert.Equal(\"container.appx\", signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsAppxContainerAndGlobAndAntiGlobPatternsAreUsed_SignsOnlyMatchingFiles()\n        {\n            const string fileListContents =\n@\"**/*.dll\n**/*.exe\n!**/*.txt\n!**/DoNotSign/**/*\";\n            ReadFileList(fileListContents, out Matcher matcher, out Matcher antiMatcher);\n\n            SignOptions options = new(\n                applicationName: \"a\",\n                publisherName: \"b\",\n                description: \"c\",\n                new Uri(\"https://description.test\"),\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                new Uri(\"https://timestamp.test\"),\n                matcher,\n                antiMatcher,\n                recurseContainers: true);\n\n            AggregatingSignerTest test = new(\n                $\"{AppxContainerName}/a.dll\",\n                $\"{AppxContainerName}/b.DLL\",\n                $\"{AppxContainerName}/c.txt\",\n                $\"{AppxContainerName}/d.exe\",\n                $\"{AppxContainerName}/e.EXE\",\n                $\"{AppxContainerName}/f/g.dll\",\n                $\"{AppxContainerName}/f/h.txt\",\n                $\"{AppxContainerName}/f/i.exe\",\n                $\"{AppxContainerName}/DoNotSign/j.dll\",\n                $\"{AppxContainerName}/DoNotSign/k.txt\",\n                $\"{AppxContainerName}/DoNotSign/l/m.txt\",\n                $\"{AppxContainerName}/DoNotSign/l/n.exe\");\n\n            await test.Signer.SignAsync(test.Files, options);\n\n            ContainerSpy container = test.Containers[AppxContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(2, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.DLL\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.exe\", signedFile.Name),\n                signedFile => Assert.Equal(\"e.EXE\", signedFile.Name),\n                signedFile => Assert.Equal(\"g.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"i.exe\", signedFile.Name),\n                signedFile => Assert.Equal(AppxContainerName, signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsEmptyZipContainer_SignsNothing()\n        {\n            AggregatingSignerTest test = new(ZipContainerName);\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[ZipContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(1, container.GetFiles_CallCount);\n            Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(0, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Empty(test.SignerSpy.SignedFiles);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsZipContainer_SignsPortableExecutableFiles()\n        {\n            AggregatingSignerTest test = new(\n                $\"{ZipContainerName}/a.dll\",\n                $\"{ZipContainerName}/b.exe\",\n                $\"{ZipContainerName}/c/d.dll\");\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            ContainerSpy container = test.Containers[ZipContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(1, container.GetFiles_CallCount);\n            Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.exe\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.dll\", signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsZipContainerWithNestedContentAndContainers_SignsContentInsideOut()\n        {\n            AggregatingSignerTest test = new(\n                $\"{ZipContainerName}/a.dll\",\n                $\"{ZipContainerName}/nestedcontainer0.zip/b.dll\",\n                $\"{ZipContainerName}/nestedcontainer0.zip/nestedcontainer1.zip/c.dll\",\n                $\"{ZipContainerName}/d.appinstaller\",\n                $\"{ZipContainerName}/nestedcontainer.nupkg/folder0/folder1/f.dll\",\n                $\"{ZipContainerName}/nestedcontainer.vsix/folder0/folder1/folder2/g.dll\");\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            foreach (string containerName in new[]\n            {\n                ZipContainerName,\n                $\"{ZipContainerName}/nestedcontainer0.zip\",\n                $\"{ZipContainerName}/nestedcontainer0.zip/nestedcontainer1.zip\",\n                $\"{ZipContainerName}/nestedcontainer.nupkg\",\n                $\"{ZipContainerName}/nestedcontainer.vsix\"\n            })\n            {\n                ContainerSpy container = test.Containers[containerName];\n\n                Assert.Equal(1, container.OpenAsync_CallCount);\n                Assert.Equal(1, container.GetFiles_CallCount);\n                Assert.Equal(0, container.GetFilesWithMatcher_CallCount);\n                Assert.Equal(1, container.SaveAsync_CallCount);\n                Assert.Equal(1, container.Dispose_CallCount);\n            }\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"c.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"f.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"g.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.appinstaller\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.nupkg\", signedFile.Name),\n                signedFile => Assert.Equal(\"nestedcontainer.vsix\", signedFile.Name));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsZipContainerAndGlobAndAntiGlobPatternsAreUsed_SignsOnlyMatchingFiles()\n        {\n            const string fileListContents =\n@\"**/*.dll\n**/*.exe\n!**/*.txt\n!**/DoNotSign/**/*\";\n            ReadFileList(fileListContents, out Matcher matcher, out Matcher antiMatcher);\n\n            SignOptions options = new(\n                applicationName: \"a\",\n                publisherName: \"b\",\n                description: \"c\",\n                new Uri(\"https://description.test\"),\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                new Uri(\"https://timestamp.test\"),\n                matcher,\n                antiMatcher,\n                recurseContainers: true);\n\n            AggregatingSignerTest test = new(\n                $\"{ZipContainerName}/a.dll\",\n                $\"{ZipContainerName}/b.DLL\",\n                $\"{ZipContainerName}/c.txt\",\n                $\"{ZipContainerName}/d.exe\",\n                $\"{ZipContainerName}/e.EXE\",\n                $\"{ZipContainerName}/f/g.dll\",\n                $\"{ZipContainerName}/f/h.txt\",\n                $\"{ZipContainerName}/f/i.exe\",\n                $\"{ZipContainerName}/DoNotSign/j.dll\",\n                $\"{ZipContainerName}/DoNotSign/k.txt\",\n                $\"{ZipContainerName}/DoNotSign/l/m.txt\",\n                $\"{ZipContainerName}/DoNotSign/l/n.exe\");\n\n            await test.Signer.SignAsync(test.Files, options);\n\n            ContainerSpy container = test.Containers[ZipContainerName];\n\n            Assert.Equal(1, container.OpenAsync_CallCount);\n            Assert.Equal(0, container.GetFiles_CallCount);\n            Assert.Equal(2, container.GetFilesWithMatcher_CallCount);\n            Assert.Equal(1, container.SaveAsync_CallCount);\n            Assert.Equal(1, container.Dispose_CallCount);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.DLL\", signedFile.Name),\n                signedFile => Assert.Equal(\"d.exe\", signedFile.Name),\n                signedFile => Assert.Equal(\"e.EXE\", signedFile.Name),\n                signedFile => Assert.Equal(\"g.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"i.exe\", signedFile.Name));\n        }\n\n        private static void ReadFileList(string contents, out Matcher matcher, out Matcher antiMatcher)\n        {\n            MatcherFactory matcherFactory = new();\n            FileListReader fileListReader = new(matcherFactory);\n\n            using (MemoryStream stream = new(Encoding.UTF8.GetBytes(contents)))\n            using (StreamReader reader = new(stream))\n            {\n                fileListReader.Read(reader, out matcher, out antiMatcher);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/AggregatingSignerTests.PortableExecutableFiles.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public partial class AggregatingSignerTests\n    {\n        [Fact]\n        public async Task SignAsync_WhenFilesAreLoosePortableExecutableFiles_SignsAllFiles()\n        {\n            string[] files = new[]\n            {\n                \"a.dll\",\n                \"directory0/a.dll\",\n                \"directory0/directory1/b.dll\",\n                \"directory2/c.dll\"\n            };\n\n            AggregatingSignerTest test = new(files);\n\n            await test.Signer.SignAsync(test.Files, _options);\n\n            Assert.Empty(test.Containers);\n\n            Assert.Collection(\n                test.SignerSpy.SignedFiles,\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"a.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"b.dll\", signedFile.Name),\n                signedFile => Assert.Equal(\"c.dll\", signedFile.Name));\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/AggregatingSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public partial class AggregatingSignerTests\n    {\n        private static readonly SignOptions _options = new(HashAlgorithmName.SHA256, new Uri(\"http://timestamp.test\"));\n\n        [Fact]\n        public void Constructor_WhenSignersIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AggregatingSigner(\n                    signers: null!,\n                    Mock.Of<IDefaultDataFormatSigner>(),\n                    Mock.Of<IContainerProvider>(),\n                    Mock.Of<IFileMetadataService>(),\n                    Mock.Of<IMatcherFactory>()));\n\n            Assert.Equal(\"signers\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenDefaultSignerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AggregatingSigner(\n                    Enumerable.Empty<IDataFormatSigner>(),\n                    defaultSigner: null!,\n                    Mock.Of<IContainerProvider>(),\n                    Mock.Of<IFileMetadataService>(),\n                    Mock.Of<IMatcherFactory>()));\n\n            Assert.Equal(\"defaultSigner\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenContainerProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AggregatingSigner(\n                    Enumerable.Empty<IDataFormatSigner>(),\n                    Mock.Of<IDefaultDataFormatSigner>(),\n                    containerProvider: null!,\n                    Mock.Of<IFileMetadataService>(),\n                    Mock.Of<IMatcherFactory>()));\n\n            Assert.Equal(\"containerProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMetadataServiceIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AggregatingSigner(\n                    Enumerable.Empty<IDataFormatSigner>(),\n                    Mock.Of<IDefaultDataFormatSigner>(),\n                    Mock.Of<IContainerProvider>(),\n                    fileMetadataService: null!,\n                    Mock.Of<IMatcherFactory>()));\n\n            Assert.Equal(\"fileMetadataService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenMatcherFactoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AggregatingSigner(\n                    Enumerable.Empty<IDataFormatSigner>(),\n                    Mock.Of<IDefaultDataFormatSigner>(),\n                    Mock.Of<IContainerProvider>(),\n                    Mock.Of<IFileMetadataService>(),\n                    matcherFactory: null!));\n\n            Assert.Equal(\"matcherFactory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            AggregatingSigner aggregatingSigner = CreateSigner();\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => aggregatingSigner.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenSignerReturnsTrue_ReturnsTrue()\n        {\n            const string extension = \".xyz\";\n\n            Mock<IDataFormatSigner> signer = new(MockBehavior.Strict);\n\n            signer.Setup(x => x.CanSign(It.IsAny<FileInfo>()))\n                .Returns(true);\n\n            AggregatingSigner aggregatingSigner = CreateSigner(signer.Object);\n\n            Assert.True(aggregatingSigner.CanSign(new FileInfo($\"file{extension}\")));\n\n            signer.VerifyAll();\n        }\n\n        [Fact]\n        public void CanSign_WhenSignerReturnsFalse_ReturnsFalse()\n        {\n            const string extension = \".xyz\";\n\n            Mock<IDataFormatSigner> signer = new(MockBehavior.Strict);\n\n            signer.Setup(x => x.CanSign(It.IsAny<FileInfo>()))\n                .Returns(false);\n\n            AggregatingSigner aggregatingSigner = CreateSigner(signer.Object);\n\n            Assert.False(aggregatingSigner.CanSign(new FileInfo($\"file{extension}\")));\n\n            signer.VerifyAll();\n        }\n\n        [Theory]\n        [InlineData(\".appxupload\")]\n        [InlineData(\".msixupload\")]\n        [InlineData(\".zip\")]\n        [InlineData(\".ZIP\")] // test case insensitivity\n        public void CanSign_WhenExtensionIsSpecialCase_ReturnsTrue(string extension)\n        {\n            AggregatingSigner aggregatingSigner = CreateSigner();\n\n            Assert.True(aggregatingSigner.CanSign(new FileInfo($\"file{extension}\")));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFilesIsNull_Throws()\n        {\n            AggregatingSigner aggregatingSigner = CreateSigner();\n\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => aggregatingSigner.SignAsync(files: null!, _options));\n\n            Assert.Equal(\"files\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenOptionsIsNull_Throws()\n        {\n            AggregatingSigner aggregatingSigner = CreateSigner();\n\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => aggregatingSigner.SignAsync(Enumerable.Empty<FileInfo>(), options: null!));\n\n            Assert.Equal(\"options\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFilesIsEmpty_Returns()\n        {\n            AggregatingSigner aggregatingSigner = CreateSigner();\n\n            await aggregatingSigner.SignAsync(Enumerable.Empty<FileInfo>(), _options);\n        }\n\n        private static AggregatingSigner CreateSigner(IDataFormatSigner? signer = null)\n        {\n            IEnumerable<IDataFormatSigner> signers;\n\n            if (signer is null)\n            {\n                signers = Enumerable.Empty<IDataFormatSigner>();\n            }\n            else\n            {\n                signers = [signer];\n            }\n\n            Mock<IMatcherFactory> matcherFactory = new();\n\n            matcherFactory.Setup(x => x.Create())\n                .Returns(new Matcher(StringComparison.OrdinalIgnoreCase));\n\n            return new AggregatingSigner(\n                signers,\n                Mock.Of<IDefaultDataFormatSigner>(),\n                Mock.Of<IContainerProvider>(),\n                Mock.Of<IFileMetadataService>(),\n                matcherFactory.Object);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/AppInstallerServiceSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Text;\nusing System.Xml.Linq;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class AppInstallerServiceSignerTests\n    {\n        private readonly AppInstallerServiceSigner _signer;\n\n        public AppInstallerServiceSignerTests()\n        {\n            _signer = new AppInstallerServiceSigner(\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<ILogger<IDataFormatSigner>>());\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppInstallerServiceSigner(\n                    certificateProvider: null!,\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new AppInstallerServiceSigner(\n                    Mock.Of<ICertificateProvider>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _signer.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".appInstaller\")] // Turkish I (U+0049)\n        [InlineData(\".appinstaller\")] // Turkish i (U+0069)\n        public void CanSign_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_signer.CanSign(file));\n        }\n\n        [Theory]\n        [InlineData(\".txt\")]\n        [InlineData(\".appİnstaller\")] // Turkish İ (U+0130)\n        [InlineData(\".appınstaller\")] // Turkish ı (U+0131)\n        public void CanSign_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_signer.CanSign(file));\n        }\n\n        [Theory]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2017\", \"MainBundle\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2017\", \"MainPackage\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2017/2\", \"MainBundle\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2017/2\", \"MainPackage\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2018\", \"MainBundle\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2018\", \"MainPackage\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2021\", \"MainBundle\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2021\", \"MainPackage\")]\n        public void TryGetMainElement_WhenNamespaceAndElementAreKnown_ReturnsElement(string xmlNamespace, string elementName)\n        {\n            CreateAppInstallerManifest(\n                xmlNamespace,\n                elementName,\n                out XDocument appInstallerManifest,\n                out string expectedPublisher);\n\n            Assert.True(AppInstallerServiceSigner.TryGetMainElement(appInstallerManifest, out XElement? mainElement));\n            Assert.NotNull(mainElement);\n\n            XAttribute? publisherAttribute = mainElement.Attribute(\"Publisher\");\n            Assert.NotNull(publisherAttribute);\n\n            Assert.Equal(expectedPublisher, publisherAttribute.Value);\n        }\n\n        [Theory]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2024\", \"MainBundle\")]\n        [InlineData(\"http://schemas.microsoft.com/appx/appinstaller/2024\", \"MainPackage\")]\n        public void TryGetMainElement_WhenNamespaceAndElementAreUnknown_ReturnsNull(string xmlNamespace, string elementName)\n        {\n            CreateAppInstallerManifest(\n                xmlNamespace,\n                elementName,\n                out XDocument appInstallerManifest,\n                out string _);\n\n            Assert.False(AppInstallerServiceSigner.TryGetMainElement(appInstallerManifest, out XElement? mainElement));\n            Assert.Null(mainElement);\n        }\n\n        private static void CreateAppInstallerManifest(\n            string xmlNamespace,\n            string mainElementName,\n            out XDocument appInstallerManifest,\n            out string expectedPublisher)\n        {\n            expectedPublisher = \"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US\";\n\n            string xml = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\" + Environment.NewLine +\n                $\"<AppInstaller xmlns=\\\"{xmlNamespace}\\\" Version=\\\"1.0.0.0\\\" Uri=\\\"http://sign.test/app.appinstaller\\\">\" + Environment.NewLine +\n                $\"  <{mainElementName} Name=\\\"sign.test\\\" Publisher=\\\"{expectedPublisher}\\\" />\" + Environment.NewLine +\n                \"</AppInstaller>\";\n\n            using (MemoryStream stream = new(Encoding.UTF8.GetBytes(xml), writable: false))\n            {\n                appInstallerManifest = XDocument.Load(stream, LoadOptions.PreserveWhitespace);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/AzureSignToolSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\nusing System.Security.Cryptography.X509Certificates;\nusing AzureSign.Core;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public sealed class AzureSignToolSignerTests : IDisposable\n    {\n        private readonly TrustedCertificateFixture _certificateFixture;\n        private readonly DirectoryService _directoryService;\n        private readonly AzureSignToolSigner _signer;\n\n        public AzureSignToolSignerTests(TrustedCertificateFixture certificateFixture)\n        {\n            ArgumentNullException.ThrowIfNull(certificateFixture, nameof(certificateFixture));\n\n            _certificateFixture = certificateFixture;\n            _directoryService = new(Mock.Of<ILogger<IDirectoryService>>());\n            _signer = new AzureSignToolSigner(\n                Mock.Of<IToolConfigurationProvider>(),\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<ILogger<IDataFormatSigner>>());\n        }\n\n        public void Dispose()\n        {\n            _directoryService.Dispose();\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _signer.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".appx\")]\n        [InlineData(\".appxbundle\")]\n        [InlineData(\".cab\")]\n        [InlineData(\".cat\")]\n        [InlineData(\".cdxml\")]\n        [InlineData(\".dll\")]\n        [InlineData(\".eappx\")]\n        [InlineData(\".eappxbundle\")]\n        [InlineData(\".emsix\")]\n        [InlineData(\".emsixbundle\")]\n        [InlineData(\".exe\")]\n        [InlineData(\".js\")]\n        [InlineData(\".msi\")]\n        [InlineData(\".msix\")]\n        [InlineData(\".msixbundle\")]\n        [InlineData(\".msm\")]\n        [InlineData(\".msp\")]\n        [InlineData(\".mst\")]\n        [InlineData(\".ocx\")]\n        [InlineData(\".ps1\")]\n        [InlineData(\".ps1xml\")]\n        [InlineData(\".psd1\")]\n        [InlineData(\".psm1\")]\n        [InlineData(\".stl\")]\n        [InlineData(\".sys\")]\n        [InlineData(\".vbs\")]\n        [InlineData(\".vxd\")]\n        [InlineData(\".winmd\")]\n        public void CanSign_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_signer.CanSign(file));\n        }\n\n\n        [Fact]\n        public void CanSign_WithNonDynamicsBusinessCentralAppFile_ReturnsFalse()\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo file = new(Path.Combine(temporaryDirectory.Directory.FullName, \"file.app\"));\n\n                File.WriteAllText(file.FullName, \"{}\");\n\n                Assert.False(_signer.CanSign(file));\n            }\n        }\n\n        [Fact]\n        public void CanSign_WithDynamicsBusinessCentralAppFile_ReturnsTrue()\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo file = new(Path.Combine(temporaryDirectory.Directory.FullName, \"file.app\"));\n\n                File.WriteAllBytes(file.FullName, new byte[] { 0x4e, 0x41, 0x56, 0x58 });\n\n                Assert.True(_signer.CanSign(file));\n            }\n        }\n\n        [Theory]\n        [InlineData(\".txt\")]\n        [InlineData(\".msİ\")] // Turkish İ (U+0130)\n        [InlineData(\".msı\")] // Turkish ı (U+0131)\n        public void CanSign_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_signer.CanSign(file));\n        }\n\n        [RequiresElevationTheory]\n        [InlineData(\"cmdlet-definition.cdxml\")]\n        [InlineData(\"script.ps1\")]\n        [InlineData(\"data.psd1\")]\n        [InlineData(\"module.psm1\")]\n        [InlineData(\"formatting.ps1xml\")]\n        public async Task SignAsync_WhenFileIsSupported_Signs(string fileName)\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo file = TestAssets.GetTestAsset(temporaryDirectory.Directory, \"PowerShell\", fileName);\n\n                SignOptions options = new(\n                    applicationName: null,\n                    publisherName: null,\n                    description: null,\n                    descriptionUrl: null,\n                    HashAlgorithmName.SHA256,\n                    HashAlgorithmName.SHA256,\n                    timestampService: null!,\n                    matcher: null,\n                    antiMatcher: null,\n                    recurseContainers: true);\n\n                X509Certificate2 certificate = _certificateFixture.TrustedCertificate;\n\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    ToolConfigurationProvider toolConfigurationProvider = new(new AppRootDirectoryLocator());\n                    Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n                    Mock<ICertificateProvider> certificateProvider = new();\n\n                    certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(new X509Certificate2(certificate));\n\n                    signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(privateKey);\n\n                    ILogger<IDataFormatSigner> logger = Mock.Of<ILogger<IDataFormatSigner>>();\n\n                    AzureSignToolSigner signer = new(\n                        toolConfigurationProvider,\n                        signatureAlgorithmProvider.Object,\n                        certificateProvider.Object,\n                        logger);\n\n                    await signer.SignAsync(new[] { file }, options);\n\n                    // Verify that the file has been renamed back.\n                    file.Refresh();\n\n                    Assert.True(file.Exists);\n\n                    PowerShellFileReader reader = PowerShellFileReader.Read(file);\n\n                    Assert.True(reader.TryGetSignature(out SignedCms? signedCms));\n\n                    SignerInfo signerInfo = (SignerInfo)Assert.Single(signedCms.SignerInfos)!;\n\n                    Assert.True(certificate.RawDataMemory.Span.SequenceEqual(signerInfo.Certificate!.RawDataMemory.Span));\n\n                    signedCms.CheckSignature(verifySignatureOnly: true);\n\n                    signatureAlgorithmProvider.VerifyAll();\n                    certificateProvider.VerifyAll();\n                }\n            }\n        }\n\n        [Theory]\n        [InlineData(\".vbs\")]\n        [InlineData(\".VBS\")]\n        [InlineData(\".Vbs\")]\n        public async Task SignAsync_WithStaRequiredFile_SignsOnStaThread(string extension)\n        {\n            using RSA rsa = RSA.Create(keySizeInBits: 2048);\n            CertificateRequest req = new(\"CN=Test\", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n            using X509Certificate2 certificate = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));\n\n            Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n            Mock<ICertificateProvider> certificateProvider = new();\n\n            certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(new X509Certificate2(certificate.Export(X509ContentType.Pfx)));\n\n            signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(RSA.Create(rsa.ExportParameters(includePrivateParameters: true)));\n\n            SignOptions options = new(\n                applicationName: null,\n                publisherName: null,\n                description: null,\n                descriptionUrl: null,\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                timestampService: null!,\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: true);\n\n            TestableAzureSignToolSigner signer = new(\n                Mock.Of<IToolConfigurationProvider>(),\n                signatureAlgorithmProvider.Object,\n                certificateProvider.Object,\n                Mock.Of<ILogger<IDataFormatSigner>>());\n\n            FileInfo file = new($\"test{extension}\");\n\n            await signer.SignAsync(new[] { file }, options);\n\n            Assert.Single(signer.SigningCalls);\n            (string FileName, ApartmentState ApartmentState) call = signer.SigningCalls.Single();\n            Assert.Equal(ApartmentState.STA, call.ApartmentState);\n        }\n\n        [Fact]\n        public async Task SignAsync_WithMixedFiles_SignsStaFilesOnStaAndNonStaInParallel()\n        {\n            using RSA rsa = RSA.Create(keySizeInBits: 2048);\n            CertificateRequest req = new(\"CN=Test\", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n            using X509Certificate2 certificate = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));\n\n            Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n            Mock<ICertificateProvider> certificateProvider = new();\n\n            certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(new X509Certificate2(certificate.Export(X509ContentType.Pfx)));\n\n            signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(RSA.Create(rsa.ExportParameters(includePrivateParameters: true)));\n\n            SignOptions options = new(\n                applicationName: null,\n                publisherName: null,\n                description: null,\n                descriptionUrl: null,\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                timestampService: null!,\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: true);\n\n            TestableAzureSignToolSigner signer = new(\n                Mock.Of<IToolConfigurationProvider>(),\n                signatureAlgorithmProvider.Object,\n                certificateProvider.Object,\n                Mock.Of<ILogger<IDataFormatSigner>>());\n\n            FileInfo[] files = new[]\n            {\n                new FileInfo(\"script1.vbs\"),\n                new FileInfo(\"library.dll\"),\n                new FileInfo(\"script2.js\"),\n                new FileInfo(\"app.exe\"),\n                new FileInfo(\"script3.VBS\"),\n            };\n\n            await signer.SignAsync(files, options);\n\n            Assert.Equal(5, signer.SigningCalls.Count);\n\n            (string FileName, ApartmentState ApartmentState)[] calls = signer.SigningCalls.ToArray();\n\n            // STA files should be signed first (sequential, before the parallel batch)\n            // and all on STA threads\n            HashSet<string> staCallNames = new(StringComparer.OrdinalIgnoreCase) { \"script1.vbs\", \"script2.js\", \"script3.VBS\" };\n            (string FileName, ApartmentState ApartmentState)[] staCalls = calls.Where(c => staCallNames.Contains(c.FileName)).ToArray();\n            Assert.Equal(3, staCalls.Length);\n            Assert.All(staCalls, c => Assert.Equal(ApartmentState.STA, c.ApartmentState));\n\n            // Non-STA files should be signed on MTA threads\n            (string FileName, ApartmentState ApartmentState)[] mtaCalls = calls.Where(c => !staCallNames.Contains(c.FileName)).ToArray();\n            Assert.Equal(2, mtaCalls.Length);\n            Assert.All(mtaCalls, c => Assert.Equal(ApartmentState.MTA, c.ApartmentState));\n\n            // STA files should appear before non-STA files in the signing order\n            // (since STA files are signed sequentially first)\n            int lastStaIndex = Array.FindLastIndex(calls, c => staCallNames.Contains(c.FileName));\n            int firstMtaIndex = Array.FindIndex(calls, c => !staCallNames.Contains(c.FileName));\n            Assert.True(lastStaIndex < firstMtaIndex,\n                $\"STA files should be signed before non-STA files. Last STA index: {lastStaIndex}, First MTA index: {firstMtaIndex}\");\n        }\n\n        [Fact]\n        public async Task SignAsync_WithNonStaFile_SignsOnMtaThread()\n        {\n            using RSA rsa = RSA.Create(keySizeInBits: 2048);\n            CertificateRequest req = new(\"CN=Test\", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n            using X509Certificate2 certificate = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));\n\n            Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n            Mock<ICertificateProvider> certificateProvider = new();\n\n            certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(new X509Certificate2(certificate.Export(X509ContentType.Pfx)));\n\n            signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                .ReturnsAsync(RSA.Create(rsa.ExportParameters(includePrivateParameters: true)));\n\n            SignOptions options = new(\n                applicationName: null,\n                publisherName: null,\n                description: null,\n                descriptionUrl: null,\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256,\n                timestampService: null!,\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: true);\n\n            TestableAzureSignToolSigner signer = new(\n                Mock.Of<IToolConfigurationProvider>(),\n                signatureAlgorithmProvider.Object,\n                certificateProvider.Object,\n                Mock.Of<ILogger<IDataFormatSigner>>());\n\n            FileInfo file = new(\"test.dll\");\n\n            await signer.SignAsync(new[] { file }, options);\n\n            Assert.Single(signer.SigningCalls);\n            (string FileName, ApartmentState ApartmentState) call = signer.SigningCalls.Single();\n            Assert.Equal(ApartmentState.MTA, call.ApartmentState);\n        }\n    }\n\n    internal class TestableAzureSignToolSigner : AzureSignToolSigner\n    {\n        public ConcurrentQueue<(string FileName, ApartmentState ApartmentState)> SigningCalls { get; } = new();\n\n        public TestableAzureSignToolSigner(\n            IToolConfigurationProvider toolConfigurationProvider,\n            ISignatureAlgorithmProvider signatureAlgorithmProvider,\n            ICertificateProvider certificateProvider,\n            ILogger<IDataFormatSigner> logger)\n            : base(toolConfigurationProvider, signatureAlgorithmProvider, certificateProvider, logger)\n        {\n        }\n\n        internal override int SignFileCore(\n            AuthenticodeKeyVaultSigner signer,\n            FileInfo file,\n            SignOptions options,\n            FileInfo manifestFile)\n        {\n            SigningCalls.Enqueue((file.Name, Thread.CurrentThread.GetApartmentState()));\n            return S_OK;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/ClickOnceSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public sealed class ClickOnceSignerTests : IDisposable\n    {\n        private readonly DirectoryService _directoryService;\n        private readonly ClickOnceSigner _signer;\n\n        public ClickOnceSignerTests()\n        {\n            _directoryService = new(Mock.Of<ILogger<IDirectoryService>>());\n            _signer = new ClickOnceSigner(\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<IServiceProvider>(),\n                Mock.Of<IMageCli>(),\n                Mock.Of<IManifestSigner>(),\n                Mock.Of<ILogger<IDataFormatSigner>>(),\n                Mock.Of<IFileMatcher>());\n        }\n\n        public void Dispose()\n        {\n            _directoryService.Dispose();\n        }\n\n        [Fact]\n        public void Constructor_WhenSignatureAlgorithmProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    signatureAlgorithmProvider: null!,\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IServiceProvider>(),\n                    Mock.Of<IMageCli>(),\n                    Mock.Of<IManifestSigner>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"signatureAlgorithmProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    certificateProvider: null!,\n                    Mock.Of<IServiceProvider>(),\n                    Mock.Of<IMageCli>(),\n                    Mock.Of<IManifestSigner>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    serviceProvider: null!,\n                    Mock.Of<IMageCli>(),\n                    Mock.Of<IManifestSigner>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenMageCliIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IServiceProvider>(),\n                    mageCli: null!,\n                    Mock.Of<IManifestSigner>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"mageCli\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenManifestSignerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IServiceProvider>(),\n                    Mock.Of<IMageCli>(),\n                    manifestSigner: null!,\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"manifestSigner\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IServiceProvider>(),\n                    Mock.Of<IMageCli>(),\n                    Mock.Of<IManifestSigner>(),\n                    logger: null!,\n                    Mock.Of<IFileMatcher>()));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ClickOnceSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IServiceProvider>(),\n                    Mock.Of<IMageCli>(),\n                    Mock.Of<IManifestSigner>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>(),\n                    fileMatcher: null!));\n\n            Assert.Equal(\"fileMatcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _signer.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".application\")]\n        [InlineData(\".APPLICATION\")] // test case insensitivity\n        [InlineData(\".vsto\")]\n        public void CanSign_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_signer.CanSign(file));\n        }\n\n        [Theory]\n        [InlineData(\".txt\")]\n        [InlineData(\".applİcation\")] // Turkish İ (U+0130)\n        [InlineData(\".applıcation\")] // Turkish ı (U+0131)\n        public void CanSign_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_signer.CanSign(file));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFilesIsNull_Throws()\n        {\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => _signer.SignAsync(\n                    files: null!,\n                    new SignOptions(HashAlgorithmName.SHA256, new Uri(\"http://timestamp.test\"))));\n\n            Assert.Equal(\"files\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenOptionsIsNull_Throws()\n        {\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => _signer.SignAsync(\n                    Enumerable.Empty<FileInfo>(),\n                    options: null!));\n\n            Assert.Equal(\"options\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningFails_Throws()\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo clickOnceFile = new(\n                    Path.Combine(\n                        temporaryDirectory.Directory.FullName,\n                        $\"{Path.GetRandomFileName()}.clickonce\"));\n\n                ContainerSpy containerSpy = new(clickOnceFile);\n\n                FileInfo applicationFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp.application\");\n\n                SignOptions options = new(\n                    \"ApplicationName\",\n                    \"PublisherName\",\n                    \"Description\",\n                    new Uri(\"https://description.test\"),\n                    HashAlgorithmName.SHA256,\n                    HashAlgorithmName.SHA256,\n                    new Uri(\"http://timestamp.test\"),\n                    matcher: null,\n                    antiMatcher: null,\n                    recurseContainers: true);\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n                    Mock<ICertificateProvider> certificateProvider = new();\n\n                    certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(certificate);\n\n                    signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(privateKey);\n\n                    Mock<IServiceProvider> serviceProvider = new();\n                    AggregatingSignerSpy aggregatingSignerSpy = new();\n\n                    serviceProvider.Setup(x => x.GetService(It.IsAny<Type>()))\n                        .Returns(aggregatingSignerSpy);\n\n                    Mock<IMageCli> mageCli = new();\n\n                    mageCli.Setup(x => x.RunAsync(\n                            It.IsAny<string>()))\n                        .ReturnsAsync(1);\n\n                    Mock<IManifestSigner> manifestSigner = new();\n                    Mock<IFileMatcher> fileMatcher = new();\n                    Mock<ILogger<IDataFormatSigner>> logger = new();\n\n                    manifestSigner.Setup(\n                        x => x.Sign(\n                            It.Is<FileInfo>(fi => fi.Name == applicationFile.Name),\n                            It.Is<X509Certificate2>(c => ReferenceEquals(certificate, c)),\n                            It.Is<RSA>(rsa => ReferenceEquals(privateKey, rsa)),\n                            It.Is<SignOptions>(o => ReferenceEquals(options, o))));\n\n                    ClickOnceSigner signer = new(\n                        signatureAlgorithmProvider.Object,\n                        certificateProvider.Object,\n                        serviceProvider.Object,\n                        mageCli.Object,\n                        manifestSigner.Object,\n                        logger.Object,\n                        fileMatcher.Object);\n\n                    signer.Retry = TimeSpan.FromMicroseconds(1);\n\n                    await Assert.ThrowsAsync<SigningException>(() => signer.SignAsync(new[] { applicationFile }, options));\n                }\n            }\n        }\n\n        [Theory]\n        [InlineData(null)]\n        [InlineData(\"PublisherName\")]\n        public async Task SignAsync_WhenFilesIsClickOnceFile_Signs(string? publisherName)\n        {\n            const string commonName = \"Test certificate (DO NOT TRUST)\";\n\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo clickOnceFile = new(\n                    Path.Combine(\n                        temporaryDirectory.Directory.FullName,\n                        $\"{Path.GetRandomFileName()}.clickonce\"));\n\n                ContainerSpy containerSpy = new(clickOnceFile);\n\n                FileInfo applicationFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp.application\");\n                FileInfo dllDeployFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp_1_0_0_0\", \"MyApp.dll.deploy\");\n                // This is an incomplete manifest --- just enough to satisfy SignAsync(...)'s requirements.\n                FileInfo manifestFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    @$\"<?xml version=\"\"1.0\"\" encoding=\"\"utf-8\"\"?>\n<asmv1:assembly xsi:schemaLocation=\"\"urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd\"\" manifestVersion=\"\"1.0\"\" xmlns:asmv1=\"\"urn:schemas-microsoft-com:asm.v1\"\" xmlns=\"\"urn:schemas-microsoft-com:asm.v2\"\" xmlns:asmv2=\"\"urn:schemas-microsoft-com:asm.v2\"\" xmlns:xsi=\"\"http://www.w3.org/2001/XMLSchema-instance\"\" xmlns:co.v1=\"\"urn:schemas-microsoft-com:clickonce.v1\"\" xmlns:asmv3=\"\"urn:schemas-microsoft-com:asm.v3\"\" xmlns:dsig=\"\"http://www.w3.org/2000/09/xmldsig#\"\" xmlns:co.v2=\"\"urn:schemas-microsoft-com:clickonce.v2\"\">\n  <publisherIdentity name=\"\"CN={commonName}, O=unit.test\"\" />\n</asmv1:assembly>\",\n                    \"MyApp_1_0_0_0\", \"MyApp.dll.manifest\");\n                FileInfo exeDeployFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp_1_0_0_0\", \"MyApp.exe.deploy\");\n                FileInfo jsonDeployFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp_1_0_0_0\", \"MyApp.json.deploy\");\n\n                SignOptions options = new(\n                    \"ApplicationName\",\n                    publisherName,\n                    \"Description\",\n                    new Uri(\"https://description.test\"),\n                    HashAlgorithmName.SHA256,\n                    HashAlgorithmName.SHA256,\n                    new Uri(\"http://timestamp.test\"),\n                    matcher: null,\n                    antiMatcher: null,\n                    recurseContainers: true);\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n                    Mock<ICertificateProvider> certificateProvider = new();\n\n                    certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(certificate);\n\n                    signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(privateKey);\n\n                    Mock<IServiceProvider> serviceProvider = new();\n                    AggregatingSignerSpy aggregatingSignerSpy = new();\n\n                    serviceProvider.Setup(x => x.GetService(It.IsAny<Type>()))\n                        .Returns(aggregatingSignerSpy);\n\n                    Mock<IMageCli> mageCli = new();\n                    string expectedArgs = $\"-update \\\"{manifestFile.FullName}\\\" -a sha256RSA -n \\\"{options.ApplicationName}\\\"\";\n                    mageCli.Setup(x => x.RunAsync(\n                            It.Is<string>(args => string.Equals(expectedArgs, args, StringComparison.Ordinal))))\n                        .ReturnsAsync(0);\n\n                    string publisher;\n\n                    if (string.IsNullOrEmpty(options.PublisherName))\n                    {\n                        publisher = certificate.SubjectName.Name;\n                    }\n                    else\n                    {\n                        publisher = options.PublisherName;\n                    }\n\n                    expectedArgs = $\"-update \\\"{applicationFile.FullName}\\\" -a sha256RSA -n \\\"{options.ApplicationName}\\\" -pub \\\"{publisher}\\\" -appm \\\"{manifestFile.FullName}\\\" -SupportURL https://description.test/\";\n                    mageCli.Setup(x => x.RunAsync(\n                            It.Is<string>(args => string.Equals(expectedArgs, args, StringComparison.Ordinal))))\n                        .ReturnsAsync(0);\n\n                    Mock<IManifestSigner> manifestSigner = new();\n                    Mock<IFileMatcher> fileMatcher = new();\n\n                    manifestSigner.Setup(\n                        x => x.Sign(\n                            It.Is<FileInfo>(fi => fi.Name == manifestFile.Name),\n                            It.Is<X509Certificate2>(c => ReferenceEquals(certificate, c)),\n                            It.Is<RSA>(rsa => ReferenceEquals(privateKey, rsa)),\n                            It.Is<SignOptions>(o => ReferenceEquals(options, o))));\n\n                    manifestSigner.Setup(\n                        x => x.Sign(\n                            It.Is<FileInfo>(fi => fi.Name == applicationFile.Name),\n                            It.Is<X509Certificate2>(c => ReferenceEquals(certificate, c)),\n                            It.Is<RSA>(rsa => ReferenceEquals(privateKey, rsa)),\n                            It.Is<SignOptions>(o => ReferenceEquals(options, o))));\n\n                    ILogger<IDataFormatSigner> logger = Mock.Of<ILogger<IDataFormatSigner>>();\n                    ClickOnceSigner signer = new(\n                        signatureAlgorithmProvider.Object,\n                        certificateProvider.Object,\n                        serviceProvider.Object,\n                        mageCli.Object,\n                        manifestSigner.Object,\n                        logger,\n                        fileMatcher.Object);\n\n                    await signer.SignAsync(new[] { applicationFile }, options);\n\n                    // Verify that files have been renamed back.\n                    foreach (FileInfo file in containerSpy.Files)\n                    {\n                        file.Refresh();\n\n                        Assert.True(file.Exists);\n                    }\n\n                    Assert.Equal(3, aggregatingSignerSpy.FilesSubmittedForSigning.Count);\n                    Assert.Collection(\n                        aggregatingSignerSpy.FilesSubmittedForSigning,\n                        file => Assert.Equal(\n                            Path.Combine(dllDeployFile.DirectoryName!, Path.GetFileNameWithoutExtension(dllDeployFile.Name)),\n                            file.FullName),\n                        file => Assert.Equal(\n                            Path.Combine(exeDeployFile.DirectoryName!, Path.GetFileNameWithoutExtension(exeDeployFile.Name)),\n                            file.FullName),\n                        file => Assert.Equal(\n                            Path.Combine(jsonDeployFile.DirectoryName!, Path.GetFileNameWithoutExtension(jsonDeployFile.Name)),\n                            file.FullName));\n\n                    mageCli.VerifyAll();\n                    manifestSigner.VerifyAll();\n                }\n            }\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFilesIsClickOnceFileWithoutContent_Signs()\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo clickOnceFile = new(\n                    Path.Combine(\n                        temporaryDirectory.Directory.FullName,\n                        $\"{Path.GetRandomFileName()}.clickonce\"));\n\n                ContainerSpy containerSpy = new(clickOnceFile);\n\n                FileInfo applicationFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp.application\");\n\n                SignOptions options = new(\n                    \"ApplicationName\",\n                    \"PublisherName\",\n                    \"Description\",\n                    new Uri(\"https://description.test\"),\n                    HashAlgorithmName.SHA256,\n                    HashAlgorithmName.SHA256,\n                    new Uri(\"http://timestamp.test\"),\n                    matcher: null,\n                    antiMatcher: null,\n                    recurseContainers: true);\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n                    Mock<ICertificateProvider> certificateProvider = new();\n\n                    certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(certificate);\n\n                    signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(privateKey);\n\n                    Mock<IServiceProvider> serviceProvider = new();\n                    AggregatingSignerSpy aggregatingSignerSpy = new();\n\n                    serviceProvider.Setup(x => x.GetService(It.IsAny<Type>()))\n                        .Returns(aggregatingSignerSpy);\n\n                    Mock<IMageCli> mageCli = new();\n\n                    string publisher;\n\n                    if (string.IsNullOrEmpty(options.PublisherName))\n                    {\n                        publisher = certificate.SubjectName.Name;\n                    }\n                    else\n                    {\n                        publisher = options.PublisherName;\n                    }\n\n                    string expectedArgs = $\"-update \\\"{applicationFile.FullName}\\\" -a sha256RSA -n \\\"{options.ApplicationName}\\\" -pub \\\"{publisher}\\\" -SupportURL https://description.test/\";\n                    mageCli.Setup(x => x.RunAsync(\n                            It.Is<string>(args => string.Equals(expectedArgs, args, StringComparison.Ordinal))))\n                        .ReturnsAsync(0);\n\n                    Mock<IManifestSigner> manifestSigner = new();\n                    Mock<IFileMatcher> fileMatcher = new();\n\n                    manifestSigner.Setup(\n                        x => x.Sign(\n                            It.Is<FileInfo>(fi => fi.Name == applicationFile.Name),\n                            It.Is<X509Certificate2>(c => ReferenceEquals(certificate, c)),\n                            It.Is<RSA>(rsa => ReferenceEquals(privateKey, rsa)),\n                            It.Is<SignOptions>(o => ReferenceEquals(options, o))));\n\n                    ILogger<IDataFormatSigner> logger = Mock.Of<ILogger<IDataFormatSigner>>();\n                    ClickOnceSigner signer = new(\n                        signatureAlgorithmProvider.Object,\n                        certificateProvider.Object,\n                        serviceProvider.Object,\n                        mageCli.Object,\n                        manifestSigner.Object,\n                        logger,\n                        fileMatcher.Object);\n\n                    await signer.SignAsync(new[] { applicationFile }, options);\n\n                    // Verify that files have been renamed back.\n                    foreach (FileInfo file in containerSpy.Files)\n                    {\n                        file.Refresh();\n\n                        Assert.True(file.Exists);\n                    }\n\n                    Assert.Empty(aggregatingSignerSpy.FilesSubmittedForSigning);\n\n                    mageCli.VerifyAll();\n                    manifestSigner.VerifyAll();\n                }\n            }\n        }\n\n        [Fact]\n        public void CopySigningDependencies_CopiesCorrectFiles()\n        {\n            using (TemporaryDirectory temporaryDirectory = new(_directoryService))\n            {\n                FileInfo clickOnceFile = new(\n                    Path.Combine(\n                        temporaryDirectory.Directory.FullName,\n                        $\"{Path.GetRandomFileName()}.clickonce\"));\n\n                ContainerSpy containerSpy = new(clickOnceFile);\n\n                FileInfo applicationFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp.application\");\n                FileInfo dllDeployFile = AddFile(\n                    containerSpy,\n                    temporaryDirectory.Directory,\n                    string.Empty,\n                    \"MyApp_1_0_0_0\", \"MyApp.dll.deploy\");\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    Mock<ISignatureAlgorithmProvider> signatureAlgorithmProvider = new();\n                    Mock<ICertificateProvider> certificateProvider = new();\n\n                    certificateProvider.Setup(x => x.GetCertificateAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(certificate);\n\n                    signatureAlgorithmProvider.Setup(x => x.GetRsaAsync(It.IsAny<CancellationToken>()))\n                        .ReturnsAsync(privateKey);\n\n                    Mock<IServiceProvider> serviceProvider = new();\n                    AggregatingSignerSpy aggregatingSignerSpy = new();\n\n                    serviceProvider.Setup(x => x.GetService(It.IsAny<Type>()))\n                        .Returns(aggregatingSignerSpy);\n\n                    Mock<IMageCli> mageCli = new();\n                    string publisher = certificate.SubjectName.Name;\n\n                    Mock<IManifestSigner> manifestSigner = new();\n                    Mock<IFileMatcher> fileMatcher = new();\n\n                    SignOptions options = new(\n                        \"ApplicationName\",\n                        \"PublisherName\",\n                        \"Description\",\n                        new Uri(\"https://description.test\"),\n                        HashAlgorithmName.SHA256,\n                        HashAlgorithmName.SHA256,\n                        new Uri(\"http://timestamp.test\"),\n                        matcher: null,\n                        antiMatcher: null,\n                        recurseContainers: true\n                    );\n\n                    manifestSigner.Setup(\n                        x => x.Sign(\n                            It.Is<FileInfo>(fi => fi.Name == applicationFile.Name),\n                            It.Is<X509Certificate2>(c => ReferenceEquals(certificate, c)),\n                            It.Is<RSA>(rsa => ReferenceEquals(privateKey, rsa)),\n                            It.Is<SignOptions>(o => ReferenceEquals(options, o))));\n\n                    ILogger<IDataFormatSigner> logger = Mock.Of<ILogger<IDataFormatSigner>>();\n                    ClickOnceSigner signer = new(\n                        signatureAlgorithmProvider.Object,\n                        certificateProvider.Object,\n                        serviceProvider.Object,\n                        mageCli.Object,\n                        manifestSigner.Object,\n                        logger,\n                        fileMatcher.Object);\n\n                    using (TemporaryDirectory signingDirectory = new(_directoryService))\n                    {\n                        // ensure that we start with nothing\n                        Assert.Empty(signingDirectory.Directory.EnumerateFiles());\n                        Assert.Empty(signingDirectory.Directory.EnumerateDirectories());\n                        // tell the provider to copy what it needs into the signing directory\n                        signer.CopySigningDependencies(applicationFile, signingDirectory.Directory, options);\n                        // and make sure we got it. We expect only the DLL to be copied, and NOT the .application file itself.\n                        IEnumerable<FileInfo> copiedFiles = signingDirectory.Directory.EnumerateFiles(\"*\", SearchOption.AllDirectories);\n                        IEnumerable<DirectoryInfo> copiedDirectories = signingDirectory.Directory.EnumerateDirectories();\n                        Assert.Single(copiedFiles);\n                        Assert.Single(copiedDirectories);\n                        Assert.Contains(copiedDirectories, d => d.Name == \"MyApp_1_0_0_0\");\n                        Assert.Contains(copiedFiles, f => f.Name == \"MyApp.dll.deploy\");\n                    }\n                }\n            }\n        }\n\n        private static FileInfo AddFile(\n            ContainerSpy containerSpy,\n            DirectoryInfo directory,\n            string fileContent,\n            params string[] fileParts)\n        {\n            string[] parts = new[] { directory.FullName }.Concat(fileParts).ToArray();\n            FileInfo file = new(Path.Combine(parts));\n\n            // The file needs to exist because it will be renamed.\n            file.Directory!.Create();\n            File.WriteAllText(file.FullName, fileContent);\n\n            containerSpy.Files.Add(file);\n\n            return file;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/DefaultSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Microsoft.Extensions.DependencyInjection;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class DefaultSignerTests\n    {\n        private static readonly SignOptions _options = new(HashAlgorithmName.SHA256, new Uri(\"http://timestamp.test\"));\n\n        [Fact]\n        public void Constructor_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new DefaultSigner(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Signer_WhenAzureSignToolSignerIsUnavailable_IsFallback()\n        {\n            DefaultSigner signer = CreateWithoutAzureSignTool();\n\n            Assert.Null(signer.Signer as IAzureSignToolDataFormatSigner);\n            Assert.False(signer.CanSign(new FileInfo(\"file.dll\")));\n        }\n\n        [Fact]\n        public void Signer_WhenAzureSignToolSignerIsAvailable_IsFallback()\n        {\n            DefaultSigner signer = CreateWithAzureSignTool();\n\n            Assert.IsAssignableFrom<IAzureSignToolDataFormatSigner>(signer.Signer);\n        }\n\n        [Fact]\n        public void CanSign_WhenAzureSignToolSignerIsUnavailable_ReturnsFalse()\n        {\n            DefaultSigner signer = CreateWithoutAzureSignTool();\n\n            Assert.False(signer.CanSign(new FileInfo(\"file.dll\")));\n        }\n\n        [Fact]\n        public void CanSign_WhenAzureSignToolSignerIsAvailable_ReturnsTrue()\n        {\n            DefaultSigner signer = CreateWithAzureSignTool();\n\n            Assert.True(signer.CanSign(new FileInfo(\"file.dll\")));\n        }\n\n        [Theory]\n        [InlineData(true)]\n        [InlineData(false)]\n        public void CanSign_WhenIAzureSignToolSignerIsAvailable_ReturnsTrue(bool expectedValue)\n        {\n            Mock<IAzureSignToolDataFormatSigner> mock = new(MockBehavior.Strict);\n\n            mock.Setup(x => x.CanSign(It.IsAny<FileInfo>()))\n                .Returns(expectedValue);\n\n            IServiceCollection services = new ServiceCollection();\n\n            services.AddLogging();\n            services.AddSingleton(Mock.Of<IToolConfigurationProvider>());\n            services.AddSingleton(Mock.Of<ISignatureAlgorithmProvider>());\n            services.AddSingleton(Mock.Of<ICertificateProvider>());\n            services.AddSingleton<IDataFormatSigner>(mock.Object);\n\n            IServiceProvider serviceProvider = services.BuildServiceProvider();\n\n            DefaultSigner signer = new(serviceProvider);\n\n            Assert.Equal(expectedValue, signer.CanSign(new FileInfo(\"file.dll\")));\n\n            mock.VerifyAll();\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFilesIsNull_Throws()\n        {\n            DefaultSigner signer = CreateWithAzureSignTool();\n\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => signer.SignAsync(files: null!, _options));\n\n            Assert.Equal(\"files\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenOptionsIsNull_Throws()\n        {\n            DefaultSigner signer = CreateWithAzureSignTool();\n\n            ArgumentNullException exception = await Assert.ThrowsAsync<ArgumentNullException>(\n                () => signer.SignAsync(Enumerable.Empty<FileInfo>(), options: null!));\n\n            Assert.Equal(\"options\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenIAzureSignToolSignerIsAvailable_InvokesInnerProvider()\n        {\n            Mock<IAzureSignToolDataFormatSigner> mock = new(MockBehavior.Strict);\n\n            mock.Setup(x => x.SignAsync(It.IsAny<IEnumerable<FileInfo>>(), It.IsAny<SignOptions>()))\n                .Returns(Task.CompletedTask);\n\n            IServiceCollection services = new ServiceCollection();\n\n            services.AddLogging();\n            services.AddSingleton(Mock.Of<IToolConfigurationProvider>());\n            services.AddSingleton(Mock.Of<ISignatureAlgorithmProvider>());\n            services.AddSingleton(Mock.Of<ICertificateProvider>());\n            services.AddSingleton<IDataFormatSigner>(mock.Object);\n\n            IServiceProvider serviceProvider = services.BuildServiceProvider();\n\n            DefaultSigner signer = new(serviceProvider);\n\n            await signer.SignAsync(Enumerable.Empty<FileInfo>(), _options);\n\n            mock.VerifyAll();\n        }\n\n        private static DefaultSigner CreateWithoutAzureSignTool()\n        {\n            IServiceCollection services = new ServiceCollection();\n            IServiceProvider serviceProvider = services.BuildServiceProvider();\n\n            return new DefaultSigner(serviceProvider);\n        }\n\n        private static DefaultSigner CreateWithAzureSignTool()\n        {\n            IServiceCollection services = new ServiceCollection();\n\n            services.AddLogging();\n            services.AddSingleton(Mock.Of<IToolConfigurationProvider>());\n            services.AddSingleton(Mock.Of<ISignatureAlgorithmProvider>());\n            services.AddSingleton(Mock.Of<ICertificateProvider>());\n            services.AddSingleton<IDataFormatSigner, AzureSignToolSigner>();\n\n            IServiceProvider serviceProvider = services.BuildServiceProvider();\n\n            return new DefaultSigner(serviceProvider);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/DistinguishedNameParserTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class DistinguishedNameParserTests\n    {\n        [Fact]\n        public void Parse_WhenSubjectIsValid_ReturnsRelativeDistinguishedNames()\n        {\n            string subject = \"CN=Microsoft Code Signing PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US\";\n\n            Dictionary<string, List<string>> result = DistinguishedNameParser.Parse(subject);\n\n            Assert.Collection(\n                result,\n                element =>\n                {\n                    Assert.Equal(\"CN\", element.Key);\n                    Assert.Equal(\"Microsoft Code Signing PCA 2011\", Assert.Single(element.Value));\n                },\n                element =>\n                {\n                    Assert.Equal(\"O\", element.Key);\n                    Assert.Equal(\"Microsoft Corporation\", Assert.Single(element.Value));\n                },\n                element =>\n                {\n                    Assert.Equal(\"L\", element.Key);\n                    Assert.Equal(\"Redmond\", Assert.Single(element.Value));\n                },\n                element =>\n                {\n                    Assert.Equal(\"S\", element.Key);\n                    Assert.Equal(\"Washington\", Assert.Single(element.Value));\n                },\n                element =>\n                {\n                    Assert.Equal(\"C\", element.Key);\n                    Assert.Equal(\"US\", Assert.Single(element.Value));\n                });\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/DynamicsBusinessCentralAppFileTypeTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public sealed class DynamicsBusinessCentralAppFileTypeTests : IDisposable\n    {\n        private readonly DirectoryService _directoryService;\n        private readonly DynamicsBusinessCentralAppFileType _fileType;\n        private readonly TemporaryDirectory _temporaryDirectory;\n\n        public DynamicsBusinessCentralAppFileTypeTests()\n        {\n            _directoryService = new DirectoryService(Mock.Of<ILogger<IDirectoryService>>());\n            _fileType = new DynamicsBusinessCentralAppFileType();\n            _temporaryDirectory = new TemporaryDirectory(_directoryService);\n        }\n\n        public void Dispose()\n        {\n            _temporaryDirectory.Dispose();\n            _directoryService.Dispose();\n        }\n\n        [Fact]\n        public void IsMatch_WhenExtensionDoesNotMatch_ReturnsFalse()\n        {\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"file.abc\"));\n\n            Assert.False(_fileType.IsMatch(file));\n        }\n\n        [Fact]\n        public void IsMatch_WhenContentIsEmpty_ReturnsFalse()\n        {\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"file.app\"));\n\n            File.WriteAllBytes(file.FullName, Array.Empty<byte>());\n\n            Assert.False(_fileType.IsMatch(file));\n        }\n\n        [Fact]\n        public void IsMatch_WhenContentDoesNotMatch_ReturnsFalse()\n        {\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"file.app\"));\n\n            File.WriteAllText(file.FullName, \"orange\");\n\n            Assert.False(_fileType.IsMatch(file));\n        }\n\n        [Theory]\n        [InlineData(\".app\")]\n        [InlineData(\".APP\")]\n        public void IsMatch_WhenExtensionAndContentMatch_ReturnsTrue(string fileExtension)\n        {\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, $\"file{fileExtension}\"));\n\n            File.WriteAllBytes(file.FullName, new byte[] { 0x4e, 0x41, 0x56, 0x58 });\n\n            Assert.True(_fileType.IsMatch(file));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/NuGetSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public class NuGetSignerTests\n    {\n        private readonly NuGetSigner _signer;\n\n        public NuGetSignerTests()\n        {\n            _signer = new NuGetSigner(\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<INuGetSignTool>(),\n                Mock.Of<ILogger<IDataFormatSigner>>());\n        }\n\n        [Fact]\n        public void Constructor_WhenSignatureAlgorithmProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetSigner(\n                    signatureAlgorithmProvider: null!,\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<INuGetSignTool>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"signatureAlgorithmProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    certificateProvider: null!,\n                    Mock.Of<INuGetSignTool>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenNuGetSignToolIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    nuGetSignTool: null!,\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"nuGetSignTool\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new NuGetSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<INuGetSignTool>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _signer.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".nupkg\")]\n        [InlineData(\".NUPKG\")] // test case insensitivity\n        [InlineData(\".snupkg\")]\n        public void CanSign_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_signer.CanSign(file));\n        }\n\n        [Fact]\n        public void CanSign_WhenFileExtensionDoesNotMatch_ReturnsFalse()\n        {\n            FileInfo file = new(\"file.txt\");\n\n            Assert.False(_signer.CanSign(file));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningFails_Throws()\n        {\n            Mock<INuGetSignTool> nuGetSignTool = new();\n\n            nuGetSignTool.Setup(\n                x => x.SignAsync(\n                    It.IsNotNull<FileInfo>(),\n                    It.IsNotNull<RSA>(),\n                    It.IsNotNull<X509Certificate2>(),\n                    It.IsNotNull<SignOptions>()))\n                .Returns(Task.FromResult(false));\n\n            NuGetSigner signer = new(\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                nuGetSignTool.Object,\n                Mock.Of<ILogger<IDataFormatSigner>>());\n\n            signer.Retry = TimeSpan.FromMicroseconds(1);\n\n            SignOptions options = new(\n                \"ApplicationName\",\n                \"PublisherName\",\n                \"Description\",\n                new Uri(\"https://description.test\"),\n                HashAlgorithmName.SHA384,\n                HashAlgorithmName.SHA384,\n                new Uri(\"http://timestamp.test\"),\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: true);\n\n            using (DirectoryService directoryService = new(Mock.Of<ILogger<IDirectoryService>>()))\n            using (TemporaryDirectory temporaryDirectory = new(directoryService))\n            {\n                FileInfo nupkgFile = TestFileCreator.CreateEmptyZipFile(temporaryDirectory, fileExtension: \".nupkg\");\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    await Assert.ThrowsAsync<SigningException>(() => signer.SignAsync([nupkgFile], options));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/PowerShell/PowerShellFileReader.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics.CodeAnalysis;\nusing System.Security.Cryptography.Pkcs;\nusing System.Text;\n\nnamespace Sign.Core.Test\n{\n    internal abstract class PowerShellFileReader\n    {\n        private readonly FileInfo _file;\n\n        protected abstract string StartComment { get; }\n        protected abstract string EndComment { get; }\n\n        protected PowerShellFileReader(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            _file = file;\n        }\n\n        internal static PowerShellFileReader Read(FileInfo file)\n        {\n            string fileExtension = file.Extension.ToLower();\n\n            return fileExtension switch\n            {\n                \".psd1\" or \".ps1\" or \".psm1\" => new TextPowerShellFileReader(file),\n                \".cdxml\" or \".ps1xml\" => new XmlPowerShellFileReader(file),\n                _ => throw new ArgumentException(message: null, paramName: nameof(file)),\n            };\n        }\n\n        internal bool TryGetSignature([NotNullWhen(true)] out SignedCms? signedCms)\n        {\n            signedCms = null;\n\n            try\n            {\n                if (!TryExtractSignatureBlock(out string? signatureBlock))\n                {\n                    return false;\n                }\n\n                byte[] signatureBytes = Convert.FromBase64String(signatureBlock);\n                signedCms = new SignedCms();\n                signedCms.Decode(signatureBytes);\n\n                return true;\n            }\n            catch (Exception)\n            {\n                signedCms = null;\n\n                return false;\n            }\n        }\n\n        private bool TryExtractSignatureBlock([NotNullWhen(true)] out string? signatureBlock)\n        {\n            signatureBlock = null;\n\n            const string sigTag = \"SIG #\";\n\n            using (FileStream stream = _file.OpenRead())\n            using (StreamReader reader = new(stream))\n            {\n                string? line = null;\n                bool signatureBlockFound = false;\n                StringBuilder base64 = new();\n\n                while ((line = reader.ReadLine()) is not null)\n                {\n                    if (!line.StartsWith(StartComment))\n                    {\n                        continue;\n                    }\n\n                    if (!signatureBlockFound)\n                    {\n                        int startIndex = line.IndexOf(sigTag, StringComparison.OrdinalIgnoreCase);\n\n                        if (startIndex >= 0)\n                        {\n                            signatureBlockFound = true;\n                        }\n\n                        continue;\n                    }\n\n                    int endIndex = line.IndexOf(sigTag, StringComparison.OrdinalIgnoreCase);\n\n                    if (endIndex >= 0)\n                    {\n                        signatureBlock = base64.ToString();\n\n                        return true;\n                    }\n\n                    string substring = line;\n\n                    while (true)\n                    {\n                        substring = substring.Trim();\n\n                        if (!string.IsNullOrEmpty(StartComment) && substring.StartsWith(StartComment))\n                        {\n                            substring = substring.Substring(StartComment.Length);\n\n                            continue;\n                        }\n\n                        if (!string.IsNullOrEmpty(EndComment) && substring.EndsWith(EndComment))\n                        {\n                            substring = substring.Substring(0, substring.Length - EndComment.Length);\n\n                            continue;\n                        }\n\n                        base64.Append(substring);\n                        break;\n                    }\n                }\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/PowerShell/TextPowerShellFileReader.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class TextPowerShellFileReader : PowerShellFileReader\n    {\n        protected override string StartComment => \"#\";\n        protected override string EndComment => string.Empty;\n\n        internal TextPowerShellFileReader(FileInfo file) : base(file)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/PowerShell/XmlPowerShellFileReader.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class XmlPowerShellFileReader : PowerShellFileReader\n    {\n        protected override string StartComment => \"<!--\";\n        protected override string EndComment => \"-->\";\n\n        internal XmlPowerShellFileReader(FileInfo file) : base(file)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/RSAPKCS1SHA256SignatureDescriptionTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    public class RSAPKCS1SHA256SignatureDescriptionTests\n    {\n        [Fact]\n        public void Constructor_Always_InitializesProperties()\n        {\n            RSAPKCS1SHA256SignatureDescription description = new();\n\n            Assert.Equal(typeof(RSA).AssemblyQualifiedName, description.KeyAlgorithm);\n            Assert.Equal(typeof(RSAPKCS1SignatureFormatter).AssemblyQualifiedName, description.FormatterAlgorithm);\n            Assert.Equal(typeof(RSAPKCS1SignatureDeformatter).AssemblyQualifiedName, description.DeformatterAlgorithm);\n            Assert.Equal(nameof(SHA256), description.DigestAlgorithm);\n        }\n\n        [Fact]\n        public void CreateDigest_Always_ReturnsSha256()\n        {\n            RSAPKCS1SHA256SignatureDescription description = new();\n\n            using (HashAlgorithm hashAlgorithm = description.CreateDigest())\n            {\n                Assert.IsAssignableFrom<SHA256>(hashAlgorithm);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/SignableFileTypeByExtensionTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class SignableFileTypeByExtensionTests\n    {\n        [Fact]\n        public void Constructor_WhenFileExtensionsIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new SignableFileTypeByExtension(fileExtensions: null!));\n            Assert.Equal(\"fileExtensions\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenFileExtensionsIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new SignableFileTypeByExtension());\n            Assert.Equal(\"fileExtensions\", exception.ParamName);\n        }\n\n        [Fact]\n        public void IsMatch_WhenFileIsNull_Throws()\n        {\n            SignableFileTypeByExtension fileType = new(fileExtensions: \".exe\");\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => fileType.IsMatch(file: null!));\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Fact]\n        public void IsMatch_WhenFileDoesNotMatch_ReturnsFalse()\n        {\n            FileInfo file = new(Path.Combine(Path.GetTempPath(), \"file.abc\"));\n            SignableFileTypeByExtension fileType = new(fileExtensions: \".exe\");\n\n            Assert.False(fileType.IsMatch(file));\n        }\n\n        [Theory]\n        [InlineData(\".exe\")]\n        [InlineData(\".EXE\")]\n        public void IsMatch_WhenFileMatches_ReturnsTrue(string fileExtension)\n        {\n            FileInfo file = new(Path.Combine(Path.GetTempPath(), $\"file{fileExtension}\"));\n            SignableFileTypeByExtension fileType = new(fileExtensions: \".exe\");\n\n            Assert.True(fileType.IsMatch(file));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/DataFormatSigners/VsixSignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public class VsixSignerTests\n    {\n        private readonly VsixSigner _signer;\n\n        public VsixSignerTests()\n        {\n            _signer = new VsixSigner(\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<IVsixSignTool>(),\n                Mock.Of<ILogger<IDataFormatSigner>>());\n        }\n\n        [Fact]\n        public void Constructor_WhenSignatureAlgorithmProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new VsixSigner(\n                    signatureAlgorithmProvider: null!,\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IVsixSignTool>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"signatureAlgorithmProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new VsixSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    certificateProvider: null!,\n                    Mock.Of<IVsixSignTool>(),\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"certificateProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenNuGetSignToolIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new VsixSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    vsixSignTool: null!,\n                    Mock.Of<ILogger<IDataFormatSigner>>()));\n\n            Assert.Equal(\"vsixSignTool\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new VsixSigner(\n                    Mock.Of<ISignatureAlgorithmProvider>(),\n                    Mock.Of<ICertificateProvider>(),\n                    Mock.Of<IVsixSignTool>(),\n                    logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CanSign_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _signer.CanSign(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(\".vsix\")]\n        [InlineData(\".VSIX\")] // test case insensitivity\n        public void CanSign_WhenFileExtensionMatches_ReturnsTrue(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.True(_signer.CanSign(file));\n        }\n\n        [Theory]\n        [InlineData(\".txt\")]\n        [InlineData(\".vsİx\")] // Turkish İ (U+0130)\n        [InlineData(\".vsıx\")] // Turkish ı (U+0131)\n        public void CanSign_WhenFileExtensionDoesNotMatch_ReturnsFalse(string extension)\n        {\n            FileInfo file = new($\"file{extension}\");\n\n            Assert.False(_signer.CanSign(file));\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningFails_Throws()\n        {\n            SignOptions options = new(\n                \"ApplicationName\",\n                \"PublisherName\",\n                \"Description\",\n                new Uri(\"https://description.test\"),\n                HashAlgorithmName.SHA384,\n                HashAlgorithmName.SHA384,\n                new Uri(\"http://timestamp.test\"),\n                matcher: null,\n                antiMatcher: null,\n                recurseContainers: true);\n\n            using (DirectoryService directoryService = new(Mock.Of<ILogger<IDirectoryService>>()))\n            using (TemporaryDirectory temporaryDirectory = new(directoryService))\n            {\n                FileInfo vsixFile = TestFileCreator.CreateEmptyZipFile(temporaryDirectory, fileExtension: \".vsix\");\n\n                using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n                using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n                {\n                    Mock<IVsixSignTool> vsixSignTool = new();\n\n                    SignConfigurationSet configuration = new(\n                        options.FileHashAlgorithm,\n                        options.FileHashAlgorithm,\n                        privateKey,\n                        certificate);\n\n                    vsixSignTool.Setup(\n                        x => x.SignAsync(\n                            It.IsNotNull<FileInfo>(),\n                            It.IsNotNull<SignConfigurationSet>(),\n                            It.IsNotNull<SignOptions>()))\n                        .Returns(Task.FromResult(false));\n\n                    VsixSigner signer = new(\n                        Mock.Of<ISignatureAlgorithmProvider>(),\n                        Mock.Of<ICertificateProvider>(),\n                        vsixSignTool.Object,\n                        Mock.Of<ILogger<IDataFormatSigner>>());\n\n                    signer.Retry = TimeSpan.FromMicroseconds(1);\n\n                    await Assert.ThrowsAsync<SigningException>(() => signer.SignAsync([vsixFile], options));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/FileList/FileListReaderTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core.Test\n{\n    public class FileListReaderTests\n    {\n        private readonly FileListReader _reader;\n\n        public FileListReaderTests()\n        {\n            _reader = new FileListReader(new MatcherSpyFactory());\n        }\n\n        [Fact]\n        public void Read_WhenReaderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _reader.Read(reader: null!, out Matcher matcher, out Matcher antiMatcher));\n\n            Assert.Equal(\"reader\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Read_WhenFileListIsEmpty_ReturnsMatcher()\n        {\n            using (StreamReader streamReader = CreateFileList())\n            {\n                _reader.Read(streamReader, out Matcher matcher, out Matcher antiMatcher);\n\n                var matcherSpy = (MatcherSpy)matcher;\n                var antiMatcherSpy = (MatcherSpy)antiMatcher;\n\n                Assert.Empty(matcherSpy.Includes);\n                Assert.Empty(matcherSpy.Excludes);\n\n                Assert.Empty(antiMatcherSpy.Includes);\n                Assert.Empty(antiMatcherSpy.Excludes);\n            }\n        }\n\n        [Theory]\n        [InlineData(\"../*\", \"*\")]\n        [InlineData(\"a/../../*\", \"a/*\")]\n        [InlineData(@\"..\\*\", \"*\")]\n        [InlineData(@\"a\\..\\..\\*\", \"a/*\")]\n        public void Read_WhenFileListContainsParentDirectoryGlobs_RemovesParentDirectoryInPattern(string input, string expectedOutput)\n        {\n            using (StreamReader streamReader = CreateFileList(input))\n            {\n                _reader.Read(streamReader, out Matcher matcher, out Matcher antiMatcher);\n\n                var matcherSpy = (MatcherSpy)matcher;\n                var antiMatcherSpy = (MatcherSpy)antiMatcher;\n\n                Assert.Equal(expectedOutput, Assert.Single(matcherSpy.Includes));\n                Assert.Empty(matcherSpy.Excludes);\n\n                Assert.Empty(antiMatcherSpy.Includes);\n                Assert.Empty(antiMatcherSpy.Excludes);\n            }\n        }\n\n        [Theory]\n        [InlineData(\"!../*\", \"*\")]\n        [InlineData(\"!a/../../*\", \"a/*\")]\n        [InlineData(@\"!..\\*\", \"*\")]\n        [InlineData(@\"!a\\..\\..\\*\", \"a/*\")]\n        public void Read_WhenFileListContainsParentDirectoryAntiGlobs_RemovesParentDirectoryInPattern(string input, string expectedOutput)\n        {\n            using (StreamReader streamReader = CreateFileList(input))\n            {\n                _reader.Read(streamReader, out Matcher matcher, out Matcher antiMatcher);\n\n                var matcherSpy = (MatcherSpy)matcher;\n                var antiMatcherSpy = (MatcherSpy)antiMatcher;\n\n                Assert.Empty(matcherSpy.Includes);\n                Assert.Empty(matcherSpy.Excludes);\n\n                Assert.Equal(expectedOutput, Assert.Single(antiMatcherSpy.Includes));\n                Assert.Empty(antiMatcherSpy.Excludes);\n            }\n        }\n\n        [Fact]\n        public void Read_WhenFileListContainsIncludes_ReturnsMatcher()\n        {\n            string[] includes = new[] { \"a/*\", \"b/*\" };\n\n            using (StreamReader streamReader = CreateFileList(includes))\n            {\n                _reader.Read(streamReader, out Matcher matcher, out Matcher antiMatcher);\n\n                var matcherSpy = (MatcherSpy)matcher;\n                var antiMatcherSpy = (MatcherSpy)antiMatcher;\n\n                Assert.Equal(includes, matcherSpy.Includes);\n                Assert.Empty(matcherSpy.Excludes);\n\n                Assert.Empty(antiMatcherSpy.Includes);\n                Assert.Empty(antiMatcherSpy.Excludes);\n            }\n        }\n\n        [Fact]\n        public void Read_WhenFileListContainsBothIncludeAndExclude_ReturnsMatcher()\n        {\n            const string include = \"**/*\";\n            const string exclude = \"!**/a.b\";\n\n            using (StreamReader streamReader = CreateFileList(include, exclude))\n            {\n                _reader.Read(streamReader, out Matcher matcher, out Matcher antiMatcher);\n\n                var matcherSpy = (MatcherSpy)matcher;\n                var antiMatcherSpy = (MatcherSpy)antiMatcher;\n\n                Assert.Equal(include, Assert.Single(matcherSpy.Includes));\n                Assert.Empty(matcherSpy.Excludes);\n\n                Assert.Equal(exclude[1..], Assert.Single(antiMatcherSpy.Includes));\n                Assert.Empty(antiMatcherSpy.Excludes);\n            }\n        }\n\n        private static StreamReader CreateFileList(params string[] lines)\n        {\n            MemoryStream stream = new();\n\n            using (StreamWriter writer = new(stream, leaveOpen: true))\n            {\n                foreach (string line in lines)\n                {\n                    writer.WriteLine(line);\n                }\n            }\n\n            stream.Seek(offset: 0, SeekOrigin.Begin);\n\n            return new StreamReader(stream);\n        }\n\n        private sealed class MatcherSpy : Matcher\n        {\n            private readonly List<string> _excludes = new();\n            private readonly List<string> _includes = new();\n\n            internal IReadOnlyList<string> Excludes\n            {\n                get => _excludes;\n            }\n\n            internal IReadOnlyList<string> Includes\n            {\n                get => _includes;\n            }\n\n            public override Matcher AddExclude(string pattern)\n            {\n                _excludes.Add(pattern);\n\n                return base.AddExclude(pattern);\n            }\n\n            public override Matcher AddInclude(string pattern)\n            {\n                _includes.Add(pattern);\n\n                return base.AddInclude(pattern);\n            }\n        }\n\n        private sealed class MatcherSpyFactory : IMatcherFactory\n        {\n            public Matcher Create()\n            {\n                return new MatcherSpy();\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/FileList/FileMatcherTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.FileSystemGlobbing.Abstractions;\n\nnamespace Sign.Core.Test\n{\n    public class FileMatcherTests\n    {\n        private static readonly bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;\n        private static readonly StringComparison StringComparison = StringComparison.OrdinalIgnoreCase;\n        private static readonly MatcherFactory MatcherFactory = new();\n\n        private readonly FileMatcher _fileMatcher;\n        private readonly Matcher _matcher;\n        private readonly string[] _files;\n        private readonly DirectoryInfoBase _directory;\n\n        public FileMatcherTests()\n        {\n            _fileMatcher = new FileMatcher();\n            _matcher = MatcherFactory.Create();\n\n            string rootDirectory = IsWindows ? @\"C:\\work\" : \"/work\";\n\n            _files = new[]\n            {\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}a\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}.b\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}c.d\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}e\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}E\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}f{Path.DirectorySeparatorChar}a\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}f{Path.DirectorySeparatorChar}.b\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}f{Path.DirectorySeparatorChar}c.d\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}f{Path.DirectorySeparatorChar}e\",\n                $\"{rootDirectory}{Path.DirectorySeparatorChar}f{Path.DirectorySeparatorChar}E\"\n            };\n            _directory = new InMemoryDirectoryInfo(rootDirectory, _files);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenDirectoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _fileMatcher.EnumerateMatches(directory: null!, _matcher));\n\n            Assert.Equal(\"directory\", exception.ParamName);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenMatcherIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _fileMatcher.EnumerateMatches(_directory, matcher: null!));\n\n            Assert.Equal(\"matcher\", exception.ParamName);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenMatcherHasInclusion_IncludesFiles()\n        {\n            _matcher.AddInclude(\"**/.b\");\n\n            IEnumerable<FileInfo> results = _fileMatcher.EnumerateMatches(_directory, _matcher);\n            string[] actual = results.Select(file => file.FullName).ToArray();\n\n            Assert.Equal(_files.Where(file => file.EndsWith(\".b\", StringComparison)), actual);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenMatcherHasOnlyExclusion_ReturnsEmptyResults()\n        {\n            _matcher.AddExclude(\"**/c.d\");\n\n            IEnumerable<FileInfo> results = _fileMatcher.EnumerateMatches(_directory, _matcher);\n\n            // Exclusions with no inclusions yields no results.\n            Assert.Empty(results);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenMatcherHasBothInclusionAndExclusion_IncludesAndExcludesFiles()\n        {\n            _matcher.AddInclude(\"**/f/*\");\n            _matcher.AddExclude(\"**/.b\");\n\n            IEnumerable<FileInfo> results = _fileMatcher.EnumerateMatches(_directory, _matcher);\n\n            string[] expected = _files.Where(file => file.Contains('f') && !file.EndsWith(\".b\", StringComparison)).ToArray();\n            string[] actual = results.Select(file => file.FullName).ToArray();\n\n            Assert.Equal(_files.Where(file => file.Contains('f') && !file.EndsWith(\".b\", StringComparison)), actual);\n        }\n\n        [Fact]\n        public void EnumerateMatches_WhenFilesDifferOnlyInCasing_AppliesMatchCaseSensitively()\n        {\n            _matcher.AddInclude(\"**/E\");\n\n            IEnumerable<FileInfo> results = _fileMatcher.EnumerateMatches(_directory, _matcher);\n            string[] actual = results.Select(file => file.FullName).ToArray();\n\n            Assert.Equal(_files.Where(file => file.EndsWith(\"E\", StringComparison)), actual);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/FileList/MatcherFactoryTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core.Test\n{\n    public class MatcherFactoryTests\n    {\n        private static readonly MatcherFactory _matcherFactory = new();\n\n        [Fact]\n        public void StringComparison_Always_IsCaseInsensitive()\n        {\n            Assert.Equal(StringComparison.OrdinalIgnoreCase, _matcherFactory.StringComparison);\n        }\n\n        [Theory]\n        [InlineData(\"file.ZIP\")] // Turkish I (U+0049)\n        [InlineData(\"file.zip\")] // Turkish i (U+0069)\n        [InlineData(\"file.zİp\")] // Turkish İ (U+0130)\n        [InlineData(\"file.zıp\")] // Turkish ı (U+0131)\n        public void Create_Always_CreatesCaseInsensitiveMatcher(string fileName)\n        {\n            bool expectedResult = string.Equals(\".zip\", Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);\n            string directoryPath = Path.GetTempPath();\n            string filePath = Path.Combine(directoryPath, fileName);\n            InMemoryDirectoryInfo directoryInfo = new(directoryPath, new[] { filePath });\n            Matcher matcher = _matcherFactory.Create();\n\n            matcher.AddInclude(\"**/*.zip\");\n\n            PatternMatchingResult result = matcher.Execute(directoryInfo);\n\n            Assert.Equal(expectedResult, result.HasMatches);\n\n            if (result.HasMatches)\n            {\n                FilePatternMatch match = Assert.Single(result.Files);\n\n                Assert.Equal(fileName, match.Path);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/FileSystem/AppRootDirectoryLocatorTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class AppRootDirectoryLocatorTests\n    {\n        [Fact]\n        public void Directory_Always_ReturnsDirectoryOfSignCoreDll()\n        {\n            DirectoryInfo expectedResult = new FileInfo(typeof(AppRootDirectoryLocator).Assembly.Location).Directory!;\n\n            AppRootDirectoryLocator locator = new();\n            DirectoryInfo actualResult = locator.Directory;\n\n            Assert.Equal(expectedResult.FullName, actualResult.FullName);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/FileSystem/DirectoryServiceTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class DirectoryServiceTests\n    {\n        private readonly Mock<ILogger<IDirectoryService>> _loggerMock;\n\n        public DirectoryServiceTests()\n        {\n            _loggerMock = new Mock<ILogger<IDirectoryService>>();\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new DirectoryService(logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CreateTemporaryDirectory_Always_CreatesDirectory()\n        {\n            using (DirectoryService service = new(_loggerMock.Object))\n            {\n                DirectoryInfo directory = service.CreateTemporaryDirectory();\n\n                Assert.NotNull(directory);\n\n                directory.Refresh();\n\n                Assert.True(directory.Exists);\n            }\n        }\n\n        [Fact]\n        public void Delete_WhenDirectoryIsNull_Throws()\n        {\n            using (DirectoryService service = new(_loggerMock.Object))\n            {\n                ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                    () => service.Delete(directory: null!));\n\n                Assert.Equal(\"directory\", exception.ParamName);\n            }\n        }\n\n        [Fact]\n        public void Delete_Always_DeletesDirectory()\n        {\n            using (DirectoryService service = new(_loggerMock.Object))\n            {\n                DirectoryInfo directory = service.CreateTemporaryDirectory();\n\n                service.Delete(directory);\n\n                directory.Refresh();\n\n                Assert.False(directory.Exists);\n            }\n        }\n\n\n        [Fact]\n        public void Dispose_Always_DeletesDirectory()\n        {\n            DirectoryInfo directory;\n\n            using (DirectoryService service = new(_loggerMock.Object))\n            {\n                directory = service.CreateTemporaryDirectory();\n\n                directory.Refresh();\n\n                Assert.True(directory.Exists);\n            }\n\n            directory.Refresh();\n\n            Assert.False(directory.Exists);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/FileSystem/FileInfoComparerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public class FileInfoComparerTests\n    {\n        private readonly FileInfoComparer _instance = FileInfoComparer.Instance;\n\n        [Fact]\n        public void Instance_Always_ReturnsSameInstance()\n        {\n            FileInfoComparer instance0 = FileInfoComparer.Instance;\n            FileInfoComparer instance1 = FileInfoComparer.Instance;\n\n            Assert.Same(instance0, instance1);\n        }\n\n        [Fact]\n        public void Equals_WhenArgumentsAreSameInstance_ReturnsTrue()\n        {\n            using (TemporaryFile temporaryFile = new())\n            {\n                Assert.True(_instance.Equals(temporaryFile.File, temporaryFile.File));\n            }\n        }\n\n        [Fact]\n        public void Equals_WhenArgumentsAreDifferentInstancesWithSameFullName_ReturnsTrue()\n        {\n            using (TemporaryFile temporaryFile = new())\n            {\n                FileInfo otherFile = new(temporaryFile.File.FullName);\n\n                Assert.True(_instance.Equals(temporaryFile.File, otherFile));\n            }\n        }\n\n        [Fact]\n        public void Equals_WhenArgumentsAreDifferentInstancesWithSameFullNameButDifferentCasing_ReturnsFalse()\n        {\n            using (TemporaryFile temporaryFile = new())\n            {\n                FileInfo oneFile = new(temporaryFile.File.FullName.ToUpperInvariant());\n                FileInfo anotherFile = new(temporaryFile.File.FullName.ToLowerInvariant());\n\n                Assert.False(_instance.Equals(oneFile, anotherFile));\n            }\n        }\n\n        [Fact]\n        public void Equals_WhenArgumentsAreDifferentInstancesWithDifferentFullName_ReturnsFalse()\n        {\n            using (TemporaryFile temporaryFile0 = new())\n            using (TemporaryFile temporaryFile1 = new())\n            {\n                Assert.False(_instance.Equals(temporaryFile0.File, temporaryFile1.File));\n            }\n        }\n\n        [Fact]\n        public void Equals_WhenOnlyOneArgumentIsNull_ReturnsFalse()\n        {\n            using (TemporaryFile temporaryFile = new())\n            {\n                Assert.False(_instance.Equals(null, temporaryFile.File));\n                Assert.False(_instance.Equals(temporaryFile.File, null));\n            }\n        }\n\n        [Fact]\n        public void Equals_WhenBothArgumentsAreNull_ReturnsTrue()\n        {\n            Assert.True(_instance.Equals(null, null));\n        }\n\n        [Fact]\n        public void GetHashCode_Always_ReturnsFullNameHashCode()\n        {\n            using (TemporaryFile temporaryFile = new())\n            {\n                Assert.Equal(\n                    temporaryFile.File.FullName.GetHashCode(),\n                    FileInfoComparer.Instance.GetHashCode(temporaryFile.File));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/FileSystem/FileMetadataServiceTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    public class FileMetadataServiceTests\n    {\n        private readonly FileMetadataService _service = new();\n\n        [Fact]\n        public void IsPortableExecutable_WhenFileIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _service.IsPortableExecutable(file: null!));\n\n            Assert.Equal(\"file\", exception.ParamName);\n        }\n\n        [Fact]\n        public void IsPortableExecutable_WhenFileIsNotMatch_ReturnsFalse()\n        {\n            using (TemporaryFile temporaryFile = CreateFakeNonPortableExecutableFile())\n            {\n                Assert.False(_service.IsPortableExecutable(temporaryFile.File));\n            }\n        }\n\n        [Fact]\n        public void IsPortableExecutable_WhenFileIsMatch_ReturnsTrue()\n        {\n            using (TemporaryFile temporaryFile = CreateFakePortableExecutableFile())\n            {\n                Assert.True(_service.IsPortableExecutable(temporaryFile.File));\n            }\n        }\n\n        private TemporaryFile CreateFakeNonPortableExecutableFile()\n        {\n            TemporaryFile temporaryFile = new();\n\n            using (FileStream stream = temporaryFile.File.OpenWrite())\n            using (StreamWriter writer = new(stream))\n            {\n                writer.Write(\"Hello, World!\");\n            }\n\n            return temporaryFile;\n        }\n\n        private TemporaryFile CreateFakePortableExecutableFile()\n        {\n            TemporaryFile temporaryFile = new();\n\n            using (FileStream stream = temporaryFile.File.OpenWrite())\n            {\n                stream.Write(\"MZ\"u8);\n            }\n\n            return temporaryFile;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/FileSystem/TemporaryDirectoryTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class TemporaryDirectoryTests\n    {\n        [Fact]\n        public void Constructor_WhenDirectoryIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new TemporaryDirectory(directoryService: null!));\n\n            Assert.Equal(\"directoryService\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_Always_CreatesDirectory()\n        {\n            using (DirectoryServiceSpy spy = new())\n            {\n                Assert.False(spy.WasCreated);\n\n                using (TemporaryDirectory directory = new(spy))\n                {\n                    Assert.True(spy.WasCreated);\n                }\n            }\n        }\n\n        [Fact]\n        public void Directory_Always_ReturnsRootDirectory()\n        {\n            using (DirectoryServiceSpy spy = new())\n            using (TemporaryDirectory directory = new(spy))\n            {\n                Assert.Equal(spy.Directory.FullName, directory.Directory.FullName);\n            }\n        }\n\n        [Fact]\n        public void Dispose_Always_DeletesDirectory()\n        {\n            using (DirectoryServiceSpy spy = new())\n            {\n                Assert.False(spy.WasDeleted);\n\n                using (TemporaryDirectory directory = new(spy))\n                {\n                }\n\n                Assert.True(spy.WasDeleted);\n            }\n        }\n\n        private sealed class DirectoryServiceSpy : IDirectoryService\n        {\n            internal DirectoryInfo Directory { get; }\n\n            internal bool WasCreated { get; private set; }\n            internal bool WasDeleted { get; private set; }\n\n            internal DirectoryServiceSpy()\n            {\n                Directory = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n\n                Directory.Create();\n            }\n\n            public DirectoryInfo CreateTemporaryDirectory()\n            {\n                WasCreated = true;\n\n                return Directory;\n            }\n\n            public void Delete(DirectoryInfo directory)\n            {\n                WasDeleted = true;\n\n                directory.Delete(recursive: true);\n            }\n\n            public void Dispose()\n            {\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Native/SignedCmiManifest2Tests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Deployment.Internal.CodeSigning;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Xml;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public class SignedCmiManifest2Tests\n    {\n        private readonly CertificatesFixture _certificatesFixture;\n\n        public SignedCmiManifest2Tests(CertificatesFixture certificatesFixture)\n        {\n            ArgumentNullException.ThrowIfNull(certificatesFixture, nameof(certificatesFixture));\n\n            _certificatesFixture = certificatesFixture;\n        }\n\n        [Fact]\n        [SuppressMessage(\"Interoperability\", \"CA1416:Validate platform compatibility\", Justification = \"<Pending>\")]\n        public void Sign_Never_GeneratesSha1MessageImprint()\n        {\n            using (X509Certificate2 certificate = SelfIssuedCertificateCreator.CreateCertificate())\n            using (X509Certificate2 publicKeyCertificate = new(certificate.Export(X509ContentType.Cert)))\n            using (RSA privateKey = certificate.GetRSAPrivateKey()!)\n            {\n                XmlDocument manifest = new() { PreserveWhitespace = true };\n\n                using (StringReader reader = new(@$\"<?xml version=\"\"1.0\"\" encoding=\"\"utf-8\"\"?>\n    <asmv1:assembly xsi:schemaLocation=\"\"urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd\"\" manifestVersion=\"\"1.0\"\" xmlns:asmv1=\"\"urn:schemas-microsoft-com:asm.v1\"\" xmlns=\"\"urn:schemas-microsoft-com:asm.v2\"\" xmlns:asmv2=\"\"urn:schemas-microsoft-com:asm.v2\"\" xmlns:xsi=\"\"http://www.w3.org/2001/XMLSchema-instance\"\" xmlns:co.v1=\"\"urn:schemas-microsoft-com:clickonce.v1\"\" xmlns:asmv3=\"\"urn:schemas-microsoft-com:asm.v3\"\" xmlns:dsig=\"\"http://www.w3.org/2000/09/xmldsig#\"\" xmlns:co.v2=\"\"urn:schemas-microsoft-com:clickonce.v2\"\">\n      <assemblyIdentity name=\"\"WinFormsApp.application\"\" version=\"\"1.0.0.0\"\" publicKeyToken=\"\"46deb9a9283e4567\"\" language=\"\"neutral\"\" processorArchitecture=\"\"msil\"\" xmlns=\"\"urn:schemas-microsoft-com:asm.v1\"\" />\n      <publisherIdentity name=\"\"{publicKeyCertificate.Subject}\"\" />\n    </asmv1:assembly>\"))\n                {\n                    manifest.Load(reader);\n                }\n\n                SignedCmiManifest2 signedCmiManifest = new(manifest);\n                CmiManifestSigner2 signer = new(privateKey, publicKeyCertificate)\n                {\n                    Flag = CmiManifestSignerFlag.DontReplacePublicKeyToken\n                };\n\n                using (TemporaryEnvironmentPathOverride temporaryEnvironmentPath = CreateTemporaryEnvironmentPathOverride())\n                {\n                    signedCmiManifest.Sign(signer, _certificatesFixture.TimestampServiceUrl.AbsoluteUri);\n                }\n\n                byte[] bytes = GetTimestampBytes(manifest);\n\n                Assert.True(\n                    Rfc3161TimestampToken.TryDecode(\n                        bytes,\n                        out Rfc3161TimestampToken? timestampToken,\n                        out int bytesConsumed));\n                Assert.True(timestampToken.TokenInfo.HashAlgorithmId.IsEqualTo(Oids.Sha256));\n            }\n        }\n\n        private static TemporaryEnvironmentPathOverride CreateTemporaryEnvironmentPathOverride()\n        {\n            string windir = Environment.GetEnvironmentVariable(\"windir\")!;\n            string netfxDir = $@\"{windir}\\Microsoft.NET\\Framework64\\v4.0.30319\";\n\n            return new TemporaryEnvironmentPathOverride(netfxDir);\n        }\n\n        private static byte[] GetTimestampBytes(XmlDocument manifest)\n        {\n            XmlNamespaceManager namespaceManager = new(manifest.NameTable);\n\n            namespaceManager.AddNamespace(\"as\", \"http://schemas.microsoft.com/windows/pki/2005/Authenticode\");\n\n            XmlNode? node = manifest.SelectSingleNode(\"//as:Timestamp\", namespaceManager);\n\n            Assert.NotNull(node);\n\n            return Convert.FromBase64String(node.InnerText);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/ServiceProviderFactoryTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.Core.Test\n{\n    public class ServiceProviderFactoryTests\n    {\n        [Fact]\n        public void AddService_ServicesIsNull_Throws()\n        {\n            var factory = new ServiceProviderFactory();\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => factory.AddServices(null!));\n\n            Assert.Equal(\"addServices\", exception.ParamName);\n        }\n\n        [Fact]\n        public void AddServices_WhenServicesAreNotAlreadyPresent_AddsServices()\n        {\n            var factory = new ServiceProviderFactory();\n            factory.AddServices(services => services.AddSingleton<ITestService, TestService>());\n            IServiceProvider serviceProvider = factory.Create();\n            Assert.NotNull(serviceProvider.GetRequiredService<ITestService>());\n        }\n\n        [Fact]\n        public void AddServices_WhenSameServiceIsNotAlreadyPresent_AddsService()\n        {\n            var factory = new ServiceProviderFactory();\n            factory.AddServices(services => services.AddSingleton<ITestService, TestService>());\n            IServiceProvider serviceProvider = factory.Create(addServices: services => services.AddSingleton<ITestService2, TestService2>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ITestService>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ITestService2>());\n        }\n\n        [Fact]\n        public void AddServices_WhenSameServiceIsAlreadyPresent_AddsService()\n        {\n            var factory = new ServiceProviderFactory();\n            factory.AddServices(services => services.AddSingleton<ITestService, TestService>());\n            IServiceProvider serviceProvider = factory.Create(addServices: services => services.AddSingleton<ITestService, TestService>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ITestService>());\n        }\n\n        [Fact]\n        public void Create_WhenNoServicesAdded_ReturnsDefault()\n        {\n            var factory = new ServiceProviderFactory();\n            IServiceProvider serviceProvider = factory.Create();\n            Assert.NotNull(serviceProvider.GetRequiredService<ILogger<ServiceProviderFactoryTests>>());\n        }\n    }\n\n    public interface ITestService\n    {\n    }\n\n    public class TestService : ITestService\n    {\n    }\n\n    public interface ITestService2\n    {\n    }\n\n    public class TestService2 : ITestService2\n    {\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/ServiceProviderTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public class ServiceProviderTests\n    {\n        [Fact]\n        public void Constructor_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ServiceProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void CreateDefault_Always_RegistersRequiredServices()\n        {\n            ServiceProvider serviceProvider = ServiceProvider.CreateDefault(\n                addServices: (IServiceCollection services) =>\n                {\n                    // Dependency injection of some services require these services.\n                    // Normally, these services are added at runtime in the CLI.\n                    services.AddSingleton<ISignatureAlgorithmProvider>(Mock.Of<ISignatureAlgorithmProvider>());\n                    services.AddSingleton<ICertificateProvider>(Mock.Of<ICertificateProvider>());\n                });\n\n            // Start of tests\n            Assert.NotNull(serviceProvider.GetRequiredService<ILogger<ServiceProviderTests>>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IAppRootDirectoryLocator>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IToolConfigurationProvider>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IMatcherFactory>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IFileListReader>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IFileMatcher>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IContainerProvider>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IFileMetadataService>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IDirectoryService>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ISignatureAlgorithmProvider>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ICertificateProvider>());\n\n            IDefaultDataFormatSigner signer = serviceProvider.GetRequiredService<IDefaultDataFormatSigner>();\n            Assert.IsType<AzureSignToolSigner>(signer.Signer);\n\n            IEnumerable<IDataFormatSigner> signers = serviceProvider.GetServices<IDataFormatSigner>();\n            Assert.Equal(5, signers.Count());\n\n            Assert.NotNull(serviceProvider.GetRequiredService<IAggregatingDataFormatSigner>());\n\n            Assert.NotNull(serviceProvider.GetRequiredService<IManifestSigner>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IMageCli>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IMakeAppxCli>());\n            Assert.NotNull(serviceProvider.GetRequiredService<INuGetSignTool>());\n            Assert.NotNull(serviceProvider.GetRequiredService<IVsixSignTool>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ICertificateVerifier>());\n            Assert.NotNull(serviceProvider.GetRequiredService<ISigner>());\n        }\n\n        [Theory]\n        [InlineData(LogLevel.Trace)]\n        [InlineData(LogLevel.Debug)]\n        [InlineData(LogLevel.Information)]\n        [InlineData(LogLevel.Warning)]\n        [InlineData(LogLevel.Error)]\n        [InlineData(LogLevel.Critical)]\n        [InlineData(LogLevel.None)]\n        public void CreateDefault_Always_ConfiguresLoggingVerbosity(LogLevel logLevel)\n        {\n            TestLoggerProvider loggerProvider = new();\n            ServiceProvider serviceProvider = ServiceProvider.CreateDefault(logLevel, loggerProvider);\n\n            ILogger logger = serviceProvider.GetRequiredService<ILogger<ServiceProviderTests>>();\n\n            logger.LogTrace(\"trace\");\n            logger.LogDebug(\"debug\");\n            logger.LogInformation(\"information\");\n            logger.LogWarning(\"warning\");\n            logger.LogError(\"error\");\n            logger.LogCritical(\"error\");\n\n            LoggerSpy loggerSpy = Assert.Single(loggerProvider.Loggers);\n\n            Assert.Equal(LogLevel.None - logLevel, loggerSpy.Logs.Count);\n\n            Assert.Equal(logLevel <= LogLevel.Trace ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Trace));\n            Assert.Equal(logLevel <= LogLevel.Debug ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Debug));\n            Assert.Equal(logLevel <= LogLevel.Information ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Information));\n            Assert.Equal(logLevel <= LogLevel.Warning ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Warning));\n            Assert.Equal(logLevel <= LogLevel.Error ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Error));\n            Assert.Equal(logLevel <= LogLevel.Critical ? 1 : 0, loggerSpy.Logs.Count(pair => pair.Key == LogLevel.Critical));\n        }\n\n        private sealed class TestLoggerProvider : ILoggerProvider\n        {\n            private readonly List<LoggerSpy> _loggers = new();\n\n            internal IReadOnlyList<LoggerSpy> Loggers => _loggers;\n\n            public ILogger CreateLogger(string categoryName)\n            {\n                LoggerSpy logger = new(categoryName);\n\n                _loggers.Add(logger);\n\n                return logger;\n            }\n\n            public void Dispose()\n            {\n            }\n        }\n\n        private sealed class LoggerSpy : ILogger\n        {\n            private readonly Dictionary<LogLevel, int> _logs = new();\n\n            internal IReadOnlyDictionary<LogLevel, int> Logs => _logs;\n\n            internal string CategoryName { get; }\n\n            internal LoggerSpy(string categoryName)\n            {\n                CategoryName = categoryName;\n            }\n\n            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)\n            {\n                if (!Logs.TryGetValue(logLevel, out int count))\n                {\n                    count = 0;\n                }\n\n                _logs[logLevel] = ++count;\n            }\n\n            public bool IsEnabled(LogLevel logLevel)\n            {\n                return true;\n            }\n\n            public IDisposable? BeginScope<TState>(TState state) where TState : notnull\n            {\n                throw new NotImplementedException();\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Sign.Core.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n    <NoWarn>$(NoWarn);NU1605</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNetCore.Server.Kestrel\" />\n    <PackageReference Include=\"Moq\" />\n    <PackageReference Include=\"AzureSign.Core\">\n      <IncludeAssets>compile;runtime</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"System.Security.Cryptography.Xml\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.Core\\Sign.Core.csproj\" />\n    <ProjectReference Include=\"..\\Sign.TestInfrastructure\\Sign.TestInfrastructure.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"TestAssets\\**\\*.*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"TestAssets\\PowerShell\\user-interface.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Sign.Core.Test/SignerTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO.Compression;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Security.Cryptography.Xml;\nusing System.Text;\nusing System.Xml;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.VisualBasic;\nusing Moq;\nusing NuGet.Packaging;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public sealed class SignerTests : IDisposable\n    {\n        private readonly CertificatesFixture _certificatesFixture;\n        private readonly DirectoryService _directoryService;\n        private readonly KeyVaultServiceStub _keyVaultServiceStub;\n        private readonly TemporaryDirectory _temporaryDirectory;\n\n        public SignerTests(CertificatesFixture certificatesFixture)\n        {\n            ArgumentNullException.ThrowIfNull(certificatesFixture, nameof(certificatesFixture));\n\n            _certificatesFixture = certificatesFixture;\n            _keyVaultServiceStub = new KeyVaultServiceStub();\n            _directoryService = new DirectoryService(Mock.Of<ILogger<IDirectoryService>>());\n            _temporaryDirectory = new TemporaryDirectory(_directoryService);\n        }\n\n        public void Dispose()\n        {\n            _keyVaultServiceStub.Dispose();\n            _temporaryDirectory.Dispose();\n            _directoryService.Dispose();\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new Signer(serviceProvider: null!, Mock.Of<ILogger<ISigner>>()));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new Signer(Mock.Of<IServiceProvider>(), logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsPortableExecutable_Signs()\n        {\n            FileInfo thisAssemblyFile = new(typeof(SignerTests).Assembly.Location);\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, thisAssemblyFile.Name));\n\n            File.Copy(thisAssemblyFile.FullName, file.FullName);\n\n            FileInfo outputFile = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"signed.dll\"));\n\n            await SignAsync(_temporaryDirectory, file, outputFile);\n\n            await VerifyAuthenticodeSignedFileAsync(outputFile);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsPowerShellScript_Signs()\n        {\n            FileInfo file = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"script.ps1\"));\n\n            File.WriteAllText(file.FullName, \"Write-Host 'Hello, World!'\");\n\n            FileInfo outputFile = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"signed.ps1\"));\n\n            await SignAsync(_temporaryDirectory, file, outputFile);\n\n            SignedCms signedCms = GetSignedCmsFromPowerShellScript(outputFile);\n\n            await VerifySignedCmsAsync(signedCms);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsVsix_Signs()\n        {\n            FileInfo file = TestAssets.GetTestAsset(_temporaryDirectory.Directory, \"VsixPackage.vsix\");\n            FileInfo outputFile = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"signed.vsix\"));\n\n            await SignAsync(_temporaryDirectory, file, outputFile);\n\n            await VerifyVsixAsync(outputFile, _temporaryDirectory);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsMsixBundle_Signs()\n        {\n            FileInfo file = TestAssets.GetTestAsset(_temporaryDirectory.Directory, \"App1_1.0.0.0_x64.msixbundle\");\n            FileInfo outputFile = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"signed.msixbundle\"));\n\n            await SignAsync(_temporaryDirectory, file, outputFile);\n\n            await VerifyMsixBundleFileAsync(outputFile, _temporaryDirectory);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenFileIsApp_Signs()\n        {\n            FileInfo file = TestAssets.GetTestAsset(_temporaryDirectory.Directory, \"EmptyExtension.app\");\n            FileInfo outputFile = new(Path.Combine(_temporaryDirectory.Directory.FullName, \"signed.app\"));\n\n            await SignAsync(_temporaryDirectory, file, outputFile);\n\n            await VerifyAppSignatureAsync(file, outputFile, _temporaryDirectory);\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningSingleFile_WithOutputDirectoryName_Signs_ToOutputDirectory()\n        {\n            FileInfo thisAssemblyFile = new(typeof(SignerTests).Assembly.Location);\n\n            FileInfo file1 = new(Path.Combine(_temporaryDirectory.Directory.FullName, thisAssemblyFile.Name));\n            var files = new[] { file1 };\n\n            foreach (var file in files)\n            {\n                File.Copy(thisAssemblyFile.FullName, file.FullName);\n            }\n\n            var outputDirectory = Path.Combine(_temporaryDirectory.Directory.FullName, \"signedFileNameWithoutExtensionIsTreatedAsDirectory\");\n\n            await SignAsync(_temporaryDirectory, files, outputDirectory);\n\n            var outputFiles = new FileInfo[]\n            {\n                  new(Path.Combine(outputDirectory, file1.Name))\n            };\n\n            foreach (var outputFile in outputFiles)\n            {\n                Assert.True(File.Exists(outputFile.FullName));\n                await VerifyAuthenticodeSignedFileAsync(outputFile);\n            }\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningMultipleFiles_WithOutputDirectoryName_Signs_ToOutputDirectory()\n        {\n            FileInfo thisAssemblyFile = new(typeof(SignerTests).Assembly.Location);\n\n            FileInfo file1 = new(Path.Combine(_temporaryDirectory.Directory.FullName, thisAssemblyFile.Name));\n            FileInfo file2 = new(Path.Combine(_temporaryDirectory.Directory.FullName, Path.ChangeExtension(thisAssemblyFile.Name, \".Copy.dll\")));\n            var files = new[] { file1, file2 };\n\n            foreach (var file in files)\n            {\n                File.Copy(thisAssemblyFile.FullName, file.FullName);\n            }\n\n            var outputDirectory = Path.Combine(_temporaryDirectory.Directory.FullName, \"signedFiles.Directory.WithExtension.dll\");\n\n            await SignAsync(_temporaryDirectory, files, outputDirectory);\n\n            var outputFiles = new FileInfo[]\n            {\n                  new(Path.Combine(outputDirectory, file1.Name)),\n                  new(Path.Combine(outputDirectory, file2.Name))\n            };\n\n            foreach (var outputFile in outputFiles)\n            {\n                Assert.True(File.Exists(outputFile.FullName));\n                await VerifyAuthenticodeSignedFileAsync(outputFile);\n            }\n        }\n\n        [Fact]\n        public async Task SignAsync_WhenSigningMultipleFiles_WithoutOutputDirectoryName_Signs_Inplace()\n        {\n            FileInfo thisAssemblyFile = new(typeof(SignerTests).Assembly.Location);\n\n            FileInfo file1 = new(Path.Combine(_temporaryDirectory.Directory.FullName, thisAssemblyFile.Name));\n            FileInfo file2 = new(Path.Combine(_temporaryDirectory.Directory.FullName, Path.ChangeExtension(thisAssemblyFile.Name, \".Copy.dll\")));\n            var files = new[] { file1, file2 };\n\n            foreach (var file in files)\n            {\n                File.Copy(thisAssemblyFile.FullName, file.FullName);\n            }\n\n            var emptyOutputDirectoryParameter = string.Empty;\n\n            await SignAsync(_temporaryDirectory, files, emptyOutputDirectoryParameter);\n\n            var outputFiles = new FileInfo[]\n            {\n                  file1,\n                  file2\n            };\n\n            foreach (var outputFile in outputFiles)\n            {\n                await VerifyAuthenticodeSignedFileAsync(outputFile);\n            }\n        }\n\n        private async Task SignAsync(TemporaryDirectory temporaryDirectory, FileInfo file, FileInfo outputFile)\n        {\n            await SignAsync(temporaryDirectory, new[] { file }, outputFile.FullName);\n        }\n\n        private async Task SignAsync(TemporaryDirectory temporaryDirectory, IReadOnlyList<FileInfo> files, string outputFile)\n        {\n            ServiceProvider serviceProvider = Create();\n            TestLogger<ISigner> logger = new();\n            Signer signer = new(serviceProvider, logger);\n\n            int exitCode = await signer.SignAsync(\n                files,\n                outputFile: outputFile,\n                fileList: null,\n                recurseContainers: true,\n                temporaryDirectory.Directory,\n                applicationName: \"a\",\n                publisherName: null,\n                description: \"b\",\n                new Uri(\"https://description.test\"),\n                _certificatesFixture.TimestampServiceUrl,\n                maxConcurrency: 4,\n                HashAlgorithmName.SHA256,\n                HashAlgorithmName.SHA256);\n\n            Assert.Equal(ExitCode.Success, exitCode);\n\n            TestLogEntry lastLogEntry = logger.Entries.Last();\n\n            Assert.Equal(LogLevel.Information, lastLogEntry.LogLevel);\n            Assert.Matches(@\"^Completed in \\d+ ms.$\", lastLogEntry.Message);\n        }\n\n        private async Task VerifyAuthenticodeSignedFileAsync(FileInfo outputFile)\n        {\n            Assert.True(AuthenticodeSignatureReader.TryGetSignedCms(outputFile, out SignedCms? signedCms));\n\n            await VerifySignedCmsAsync(signedCms);\n        }\n\n        private async Task VerifyMsixBundleFileAsync(FileInfo outputFile, TemporaryDirectory temporaryDirectory)\n        {\n            using (FileStream fileStream = outputFile.OpenRead())\n            using (ZipArchive msixBundle = new(fileStream))\n            {\n                await VerifyAppxSignatureAsync(msixBundle);\n\n                ZipArchiveEntry? entry = msixBundle.GetEntry(\"App1_1.0.0.0_x64.msix\");\n\n                Assert.NotNull(entry);\n\n                using (Stream msixStream = entry.Open())\n                using (ZipArchive msix = new(msixStream))\n                {\n                    await VerifyAppxSignatureAsync(msix);\n\n                    foreach (string entryPath in new[]\n                    {\n                        \"AppxMetadata/CodeIntegrity.cat\",\n                        \"App1.dll\",\n                        \"App1.exe\",\n                        \"clrcompression.dll\",\n                    })\n                    {\n                        entry = msix.GetEntry(entryPath);\n\n                        Assert.NotNull(entry);\n\n                        FileInfo extractedFile = ExtractEntry(temporaryDirectory, entry);\n\n                        await VerifyAuthenticodeSignedFileAsync(extractedFile);\n                    }\n                }\n            }\n        }\n\n        private async Task VerifyVsixAsync(FileInfo outputFile, TemporaryDirectory temporaryDirectory)\n        {\n            using (FileStream fileStream = outputFile.OpenRead())\n            using (ZipArchive vsix = new(fileStream))\n            {\n                ZipArchiveEntry? dllEntry = vsix.GetEntry(\"VsixPackage.dll\");\n\n                Assert.NotNull(dllEntry);\n\n                FileInfo extractedFile = ExtractEntry(temporaryDirectory, dllEntry);\n\n                await VerifyAuthenticodeSignedFileAsync(extractedFile);\n\n                Assert.True(TryGetSignatureEntry(vsix, out ZipArchiveEntry? signatureEntry));\n\n                extractedFile = ExtractEntry(temporaryDirectory, signatureEntry);\n\n                await VerifyXmlDsigAsync(extractedFile);\n            }\n        }\n\n        private static FileInfo ExtractEntry(TemporaryDirectory temporaryDirectory, ZipArchiveEntry entry)\n        {\n            FileInfo file = new(Path.Combine(temporaryDirectory.Directory.FullName, entry.Name));\n\n            using (Stream stream = entry.Open())\n            {\n                stream.CopyToFile(file.FullName);\n            }\n\n            return file;\n        }\n\n        private async Task VerifyAppSignatureAsync(FileInfo unsignedAppFile, FileInfo signedAppFile, TemporaryDirectory temporaryDirectory)\n        {\n            FileInfo signatureFile = new(Path.Combine(temporaryDirectory.Directory.FullName, \"signature.p7s\"));\n\n            if (await TryExtractSignatureBlockAsync(unsignedAppFile, signedAppFile, signatureFile))\n            {\n                SignedCms signedCms = GetSignedCms(signatureFile);\n\n                await VerifySignedCmsAsync(signedCms);\n            }\n            else\n            {\n                Assert.Fail(\"The file is not signed.\");\n            }\n        }\n\n        private static async Task<bool> TryExtractSignatureBlockAsync(\n            FileInfo unsignedAppFile,\n            FileInfo signedAppFile,\n            FileInfo signatureFile)\n        {\n            // NAVX signature block marker\n            ReadOnlyMemory<byte> nxsb = Encoding.UTF8.GetBytes(\"NXSB\");\n\n            long endOfUnsignedApp = unsignedAppFile.Length;\n\n            using (BinaryReader reader = new(signedAppFile.OpenRead()))\n            {\n                reader.BaseStream.Seek(endOfUnsignedApp, SeekOrigin.Begin);\n\n                byte[] bytes = reader.ReadBytes(nxsb.Length);\n\n                if (nxsb.Span.SequenceEqual(bytes))\n                {\n                    using (FileStream signatureStream = signatureFile.OpenWrite())\n                    {\n                        await reader.BaseStream.CopyToAsync(signatureStream);\n\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        private async Task VerifyAppxSignatureAsync(ZipArchive msix)\n        {\n            ZipArchiveEntry? entry = msix.GetEntry(\"AppxSignature.p7x\");\n\n            Assert.NotNull(entry);\n\n            SignedCms signedCms = GetSignedCms(entry);\n\n            await VerifySignedCmsAsync(signedCms);\n        }\n\n        private async Task VerifyXmlDsigAsync(FileInfo extractedFile)\n        {\n            XmlDocument xmlDoc = new()\n            {\n                PreserveWhitespace = true\n            };\n            xmlDoc.Load(extractedFile.FullName);\n\n            SignedXml signedXml = new(xmlDoc);\n            XmlNodeList nodes = xmlDoc.GetElementsByTagName(\"Signature\");\n            XmlElement? node = Assert.Single(nodes) as XmlElement;\n\n            Assert.NotNull(node);\n\n            signedXml.LoadXml(node);\n\n            using (X509Certificate2 expectedCertificate = await _keyVaultServiceStub.GetCertificateAsync())\n            {\n                Assert.True(signedXml.CheckSignature(expectedCertificate, verifySignatureOnly: true));\n            }\n\n            nodes = xmlDoc.GetElementsByTagName(\"EncodedTime\");\n            node = Assert.Single(nodes) as XmlElement;\n\n            Assert.NotNull(node);\n\n            SignedCms signedCms = GetSignedCmsFromBase64(node.InnerText);\n\n            VerifyTimestampSignedCms(signedCms);\n        }\n\n        private static SignedCms GetSignedCms(ZipArchiveEntry entry)\n        {\n            Memory<byte> buffer = new byte[entry.Length];\n\n            using (Stream stream = entry!.Open())\n            {\n                stream.Read(buffer.Span);\n            }\n\n            SignedCms signedCms = new();\n\n            // The first 4 bytes are 0x504B4358 (\"PKCX\").\n            signedCms.Decode(buffer[4..].Span);\n\n            return signedCms;\n        }\n\n        private static SignedCms GetSignedCms(FileInfo file)\n        {\n            byte[] bytes = File.ReadAllBytes(file.FullName);\n            SignedCms signedCms = new();\n\n            signedCms.Decode(bytes);\n\n            return signedCms;\n        }\n\n        private static SignedCms GetSignedCmsFromBase64(string base64)\n        {\n            byte[] bytes = Convert.FromBase64String(base64);\n            SignedCms signedCms = new();\n\n            signedCms.Decode(bytes);\n\n            return signedCms;\n        }\n\n        private static SignedCms GetSignedCmsFromPowerShellScript(FileInfo file)\n        {\n            StringBuilder base64 = new();\n\n            using (FileStream stream = file.OpenRead())\n            using (StreamReader reader = new(stream))\n            {\n                string? line;\n\n                while ((line = reader.ReadLine()) is not null)\n                {\n                    if (!line.StartsWith(\"#\"))\n                    {\n                        continue;\n                    }\n\n                    line = line.Trim('#', ' ');\n\n                    if (line.StartsWith(\"SIG #\"))\n                    {\n                        continue;\n                    }\n\n                    base64.Append(line);\n                }\n            }\n\n            return GetSignedCmsFromBase64(base64.ToString());\n        }\n\n        private static bool TryGetSignatureEntry(ZipArchive zipArchive, [NotNullWhen(true)] out ZipArchiveEntry? signatureEntry)\n        {\n            signatureEntry = null;\n\n            foreach (ZipArchiveEntry entry in zipArchive.Entries)\n            {\n                if (entry.FullName.StartsWith(\"package/services/digital-signature/xml-signature/\"))\n                {\n                    signatureEntry = entry;\n\n                    break;\n                }\n            }\n\n            return signatureEntry is not null;\n        }\n\n        private async Task VerifySignedCmsAsync(SignedCms signedCms)\n        {\n            SignerInfo signerInfo = signedCms.SignerInfos[0];\n\n            using (X509Certificate2 expectedCertificate = await _keyVaultServiceStub.GetCertificateAsync())\n            {\n                Assert.True(expectedCertificate.Equals(signerInfo.Certificate));\n            }\n\n            signerInfo.CheckSignature(verifySignatureOnly: true);\n\n            Assert.True(TryGetTimestampSignedCms(signerInfo, out SignedCms? timestampSignedCms));\n\n            VerifyTimestampSignedCms(timestampSignedCms);\n        }\n\n        private void VerifyTimestampSignedCms(SignedCms timestampSignedCms)\n        {\n            SignerInfo timestampSignerInfo = timestampSignedCms.SignerInfos[0];\n\n            Assert.True(_certificatesFixture.TimestampServiceCertificate.Equals(timestampSignerInfo.Certificate));\n\n            timestampSignerInfo.CheckSignature(verifySignatureOnly: true);\n        }\n\n        private static bool TryGetTimestampSignedCms(SignerInfo signerInfo, [NotNullWhen(true)] out SignedCms? timestampSignedCms)\n        {\n            timestampSignedCms = null;\n\n            CryptographicAttributeObjectCollection unsignedAttributes = signerInfo.UnsignedAttributes;\n\n            foreach (CryptographicAttributeObject attribute in unsignedAttributes)\n            {\n                if (attribute.Oid.IsEqualTo(Oids.MicrosoftRfc3161Timestamp))\n                {\n                    foreach (AsnEncodedData value in attribute.Values)\n                    {\n                        SignedCms signedCms = new();\n\n                        signedCms.Decode(value.RawData);\n\n                        timestampSignedCms = signedCms;\n\n                        break;\n                    }\n                }\n            }\n\n            return timestampSignedCms is not null;\n        }\n\n        private ServiceProvider Create()\n        {\n            ServiceCollection services = new();\n\n            services.AddLogging();\n\n            services.AddSingleton<IAppRootDirectoryLocator, AppRootDirectoryLocator>();\n            services.AddSingleton<IToolConfigurationProvider, ToolConfigurationProvider>();\n            services.AddSingleton<IMatcherFactory, MatcherFactory>();\n            services.AddSingleton<IFileListReader, FileListReader>();\n            services.AddSingleton<IFileMatcher, FileMatcher>();\n            services.AddSingleton<IContainerProvider, ContainerProvider>();\n            services.AddSingleton<IFileMetadataService, FileMetadataService>();\n            services.AddSingleton<IDirectoryService, DirectoryService>();\n            services.AddSingleton<ISignatureAlgorithmProvider>(_keyVaultServiceStub);\n            services.AddSingleton<ICertificateProvider>(_keyVaultServiceStub);\n            services.AddSingleton<IDataFormatSigner, AzureSignToolSigner>();\n            services.AddSingleton<IDataFormatSigner, ClickOnceSigner>();\n            services.AddSingleton<IDataFormatSigner, VsixSigner>();\n            services.AddSingleton<IDataFormatSigner, NuGetSigner>();\n            services.AddSingleton<IDataFormatSigner, AppInstallerServiceSigner>();\n            services.AddSingleton<IDefaultDataFormatSigner, DefaultSigner>();\n            services.AddSingleton<IAggregatingDataFormatSigner, AggregatingSigner>();\n            services.AddSingleton<IManifestSigner, ManifestSigner>();\n            services.AddSingleton<IMageCli, MageCli>();\n            services.AddSingleton<IMakeAppxCli, MakeAppxCli>();\n            services.AddSingleton<INuGetSignTool, NuGetSignTool>();\n            services.AddSingleton<IVsixSignTool, VsixSignTool>();\n            services.AddSingleton<ICertificateVerifier, CertificateVerifier>();\n            services.AddSingleton<ISigner, Signer>();\n\n            return new ServiceProvider(services.BuildServiceProvider());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestAssets/PowerShell/cmdlet-definition.cdxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<CmdletDefinition xmlns=\"http://schemas.microsoft.com/cmdlets-over-objects/2009/11\">\n    <Cmdlets>\n        <Cmdlet>\n            <Verb>Write</Verb>\n            <Noun>HelloWorld</Noun>\n            <HelpFile>Write-HelloWorld</HelpFile>\n            <Parameters>\n                <Parameter>\n                    <Name>Message</Name>\n                    <ParameterType>System.String</ParameterType>\n                    <Position>0</Position>\n                    <Mandatory>true</Mandatory>\n                </Parameter>\n            </Parameters>\n            <MethodName>WriteHelloWorld</MethodName>\n        </Cmdlet>\n    </Cmdlets>\n    <ClassDefinitions>\n        <ClassDefinition>\n            <ClassName>HelloWorldCmdlet</ClassName>\n            <Methods>\n                <Method>\n                    <Name>WriteHelloWorld</Name>\n                    <ReturnType>System.Void</ReturnType>\n                    <Parameters>\n                        <Parameter>\n                            <Name>Message</Name>\n                            <ParameterType>System.String</ParameterType>\n                        </Parameter>\n                    </Parameters>\n                    <Script>\n                        <![CDATA[\n                            param($Message)\n                            Write-Output \"Hello, World! $Message\"\n                        ]]>\n                    </Script>\n                </Method>\n            </Methods>\n        </ClassDefinition>\n    </ClassDefinitions>\n</CmdletDefinition>"
  },
  {
    "path": "test/Sign.Core.Test/TestAssets/PowerShell/data.psd1",
    "content": "﻿@{\n    Greeting = 'Hello, World!'\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestAssets/PowerShell/formatting.ps1xml",
    "content": "﻿<Configuration>\n    <ViewDefinitions>\n        <View>\n            <Name>HelloWorldView</Name>\n            <ViewSelectedBy>\n                <TypeName>System.String</TypeName>\n            </ViewSelectedBy>\n            <TableControl>\n                <TableHeaders>\n                    <TableColumnHeader>\n                        <Label>Greeting</Label>\n                        <Width>20</Width>\n                    </TableColumnHeader>\n                </TableHeaders>\n                <TableRowEntries>\n                    <TableRowEntry>\n                        <TableColumnItems>\n                            <TableColumnItem>\n                                <PropertyName>Greeting</PropertyName>\n                            </TableColumnItem>\n                        </TableColumnItems>\n                    </TableRowEntry>\n                </TableRowEntries>\n            </TableControl>\n        </View>\n    </ViewDefinitions>\n</Configuration>"
  },
  {
    "path": "test/Sign.Core.Test/TestAssets/PowerShell/module.psm1",
    "content": "﻿Function Get-HelloWorld\n{\n    Write-Output 'Hello, World!'\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestAssets/PowerShell/script.ps1",
    "content": "﻿Write-Output 'Hello, World!'"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/AggregatingSignerSpy.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class AggregatingSignerSpy : IAggregatingDataFormatSigner\n    {\n        internal List<FileInfo> FilesSubmittedForSigning { get; } = new();\n\n        public bool CanSign(FileInfo file)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            FilesSubmittedForSigning.AddRange(files);\n\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/AggregatingSignerTest.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class AggregatingSignerTest\n    {\n        private readonly ContainerProviderStub _containerProvider;\n\n        internal Dictionary<string, ContainerSpy> Containers { get; }\n        internal IEnumerable<FileInfo> Files { get; }\n        internal AggregatingSigner Signer { get; }\n        internal SignerSpy SignerSpy { get; }\n\n        /// <summary>\n        /// Creates a test for testing <see cref=\"AggregatingSigner\" />.\n        /// </summary>\n        /// <param name=\"paths\">Zero or more relative file or directory paths.</param>\n        /// <remarks>\n        /// All paths:\n        ///\n        ///     * must use only forward slashes (/) to delimit files and directories\n        ///\n        ///         Examples:\n        ///           ❌ directory\\a.dll\n        ///           ✔️ directory/a.dll\n        ///\n        ///     * must not begin with a forward slash (/)\n        ///\n        ///         Examples:\n        ///           ❌ /a.dll\n        ///           ❌ /directory/b.dll\n        ///           ✔️ a.dll\n        ///           ✔️ directory/b.dll\n        /// \n        ///     * must not contain current (.) or parent (..) directory specifiers\n        ///\n        ///         Examples:\n        ///           ❌ ./a.dll\n        ///           ❌ ../b.dll\n        ///           ❌ directory/../c.dll\n        ///           ✔️ a.dll\n        ///           ✔️ directory/c.dll\n        ///\n        ///     * must be a relative path relative to the same arbitrary root path\n        ///\n        ///         Examples:\n        ///           ❌ C:\\a.dll\n        ///           ❌ //directory/b.dll\n        ///           ✔️ a.dll\n        ///           ✔️ directory/b.dll\n        ///\n        ///     * must represent a file or directory, but paths that represent a directory must have\n        ///       a trailing forward slash (/) to distinguish them from a file\n        ///\n        ///         Examples:\n        ///           ❌ a.dll/\n        ///           ❌ directory\n        ///           ❌ directory/subdirectory\n        ///           ✔️ a.dll\n        ///           ✔️ directory/\n        ///           ✔️ directory/subdirectory/\n        /// \n        ///     * should treat a container file as a file when the entire path represents a container file and\n        ///       should treat a container file as a directory when the entire path represents a file or\n        ///       directory within the container file\n        ///\n        ///         Examples:\n        ///           ❌ container.zip/\n        ///           ✔️ container.zip/a.dll\n        ///           ✔️ container.zip/directory/b.dll\n        ///           ✔️ container.zip/nestedcontainer.zip/directory/c.dll\n        ///\n        /// </remarks>\n        internal AggregatingSignerTest(params string[] paths)\n        {\n            _containerProvider = new ContainerProviderStub();\n            Containers = new Dictionary<string, ContainerSpy>(StringComparer.Ordinal);\n            SignerSpy = new SignerSpy();\n\n            HashSet<FileInfo> looseFiles = new(FileInfoComparer.Instance);\n            AzureSignToolSigner azureSignToolSigner = new(\n                Mock.Of<IToolConfigurationProvider>(),\n                Mock.Of<ISignatureAlgorithmProvider>(),\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<ILogger<IDataFormatSigner>>());\n            FileMetadataServiceStub fileMetadataService = new();\n\n            // This directory doesn't actually exist or even need to exist.\n            // It is only used to construct rooted file paths in memory.\n            DirectoryInfo rootDirectory = new(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n\n            foreach (string path in paths)\n            {\n                int startIndex = 0;\n                int lastEndIndex = startIndex;\n                int endIndex;\n                HashSet<FileInfo> files = looseFiles;\n                string? relativePath;\n                bool isDirectory = false;\n\n                do\n                {\n                    endIndex = path.IndexOf('/', lastEndIndex);\n\n                    if (endIndex == -1)\n                    {\n                        relativePath = path[0..(path.Length)];\n                    }\n                    else if (endIndex == path.Length - 1)\n                    {\n                        // It's a directory because it has a trailing slash.\n                        relativePath = path[0..(path.Length)];\n                        isDirectory = true;\n\n                        endIndex = -1;\n                    }\n                    else\n                    {\n                        relativePath = path[0..endIndex];\n                    }\n\n                    string fullPath = new(Path.Combine(rootDirectory.FullName, relativePath.Replace('/', Path.DirectorySeparatorChar)));\n                    FileInfo file = new(fullPath);\n\n                    if (!isDirectory &&\n                        (_containerProvider.IsAppxBundleContainer(file) ||\n                        _containerProvider.IsAppxContainer(file) ||\n                        _containerProvider.IsNuGetContainer(file) ||\n                        _containerProvider.IsZipContainer(file)))\n                    {\n                        files.Add(file);\n\n                        if (!Containers.TryGetValue(relativePath, out ContainerSpy? container))\n                        {\n                            container = Containers[relativePath] = new ContainerSpy(file);\n                        }\n\n                        files = container.Files;\n\n                        if (endIndex != -1)\n                        {\n                            startIndex = lastEndIndex = endIndex + 1;\n                        }\n                    }\n                    else if (endIndex == -1)\n                    {\n                        files.Add(file);\n\n                        if (azureSignToolSigner.CanSign(file))\n                        {\n                            fileMetadataService.PortableExecutableFiles.Add(file);\n                        }\n                    }\n                    else\n                    {\n                        lastEndIndex = endIndex + 1;\n                    }\n                } while (endIndex >= 0);\n            }\n\n            List<string> inMemoryFiles = looseFiles.Select(looseFile => looseFile.FullName).ToList();\n            InMemoryDirectoryInfo inMemoryDirectoryInfo = new(rootDirectory.FullName, inMemoryFiles);\n            FileMatcher fileMatcher = new();\n            Matcher matcher = new();\n\n            matcher.AddInclude(\"**/*\");\n\n            Files = fileMatcher.EnumerateMatches(inMemoryDirectoryInfo, matcher).ToList();\n            Signer = new AggregatingSigner(\n                [SignerSpy],\n                SignerSpy,\n                _containerProvider,\n                fileMetadataService,\n                new MatcherFactory());\n            _containerProvider.Containers = Containers.Values.ToList();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/AuthenticodeSignatureReader.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.InteropServices;\nusing System.Security.Cryptography.Pkcs;\n\nnamespace Sign.Core.Test\n{\n    internal static class AuthenticodeSignatureReader\n    {\n        private const string Crypt32Dll = \"Crypt32.dll\";\n        private const int CERT_QUERY_OBJECT_FILE = 0x00000001;\n        private const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10;\n        private const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = (1 << CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED);\n        private const int CERT_QUERY_FORMAT_BINARY = 1;\n        private const int CERT_QUERY_FORMAT_FLAG_BINARY = (1 << CERT_QUERY_FORMAT_BINARY);\n        private const int CMSG_ENCODED_MESSAGE = 29;\n\n        internal static bool TryGetSignedCms(FileInfo file, [NotNullWhen(true)] out SignedCms? signedCms)\n        {\n            signedCms = null;\n\n            byte[] blob = GetSignedCmsBlob(file);\n\n            if (blob is not null && blob.Length > 0)\n            {\n                SignedCms cms = new();\n\n                cms.Decode(blob);\n\n                signedCms = cms;\n            }\n\n            return signedCms is not null;\n        }\n\n        private static byte[] GetSignedCmsBlob(FileInfo file)\n        {\n            IntPtr pvObject = Marshal.StringToHGlobalUni(file.FullName);\n            IntPtr phCertStore = IntPtr.Zero;\n            IntPtr phMsg = IntPtr.Zero;\n            byte[]? pvData = null;\n\n            try\n            {\n                IntPtr ppvContext = IntPtr.Zero;\n\n                if (!CryptQueryObject(\n                    CERT_QUERY_OBJECT_FILE,\n                    pvObject,\n                    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,\n                    CERT_QUERY_FORMAT_FLAG_BINARY,\n                    dwFlags: 0,\n                    out int pdwMsgAndCertEncodingType,\n                    out int pdwContentType,\n                    out int pdwFormatType,\n                    ref phCertStore,\n                    ref phMsg,\n                    ref ppvContext))\n                {\n                    throw new Win32Exception();\n                }\n\n                int pcbData = 0;\n\n                if (!CryptMsgGetParam(phMsg, CMSG_ENCODED_MESSAGE, dwIndex: 0, IntPtr.Zero, ref pcbData))\n                {\n                    throw new Win32Exception();\n                }\n\n                pvData = new byte[pcbData];\n\n                if (!CryptMsgGetParam(phMsg, CMSG_ENCODED_MESSAGE, dwIndex: 0, pvData, ref pcbData))\n                {\n                    throw new Win32Exception();\n                }\n            }\n            finally\n            {\n                if (phMsg != IntPtr.Zero)\n                {\n                    CryptMsgClose(phMsg);\n                }\n\n                if (phCertStore != IntPtr.Zero)\n                {\n                    CertCloseStore(phCertStore, dwFlags: 0);\n                }\n\n                if (pvObject != IntPtr.Zero)\n                {\n                    Marshal.FreeHGlobal(pvObject);\n                }\n            }\n\n            return pvData;\n        }\n\n        [DllImport(Crypt32Dll, CharSet = CharSet.Auto, SetLastError = true)]\n        private static extern bool CertCloseStore(\n            /* HCERTSTORE */ [In] IntPtr hCertStore,\n            /* DWORD */ [In] int dwFlags);\n\n        [DllImport(Crypt32Dll, CharSet = CharSet.Auto, SetLastError = true)]\n        private static extern bool CryptMsgClose(\n            /* HCRYPTMSG */ [In] IntPtr hCryptMsg);\n\n        [DllImport(Crypt32Dll, CharSet = CharSet.Auto, SetLastError = true)]\n        private static extern bool CryptQueryObject(\n            /* DWORD */ [In] int dwObjectType,\n            /* const void* */ [In] IntPtr pvObject,\n            /* DWORD */ [In] int dwExpectedContentTypeFlags,\n            /* DWORD */ [In] int dwExpectedFormatTypeFlags,\n            /* DWORD */ [In] int dwFlags,\n            /* DWORD* */ [Out] out int pdwMsgAndCertEncodingType,\n            /* DWORD* */ [Out] out int pdwContentType,\n            /* DWORD* */ [Out] out int pdwFormatType,\n            /* HCERTSTORE* */ ref IntPtr phCertStore,\n            /* HCRYPTMSG* */ ref IntPtr phMsg,\n            /* const void** */ ref IntPtr ppvContext);\n\n        [DllImport(Crypt32Dll, CharSet = CharSet.Auto, SetLastError = true)]\n        private static extern bool CryptMsgGetParam(\n            /* HCRYPTMSG */ [In] IntPtr hCryptMsg,\n            /* DWORD */ [In] int dwParamType,\n            /* DWORD */ [In] int dwIndex,\n            /* void* */ [In, Out] IntPtr pvData,\n            /* DWORD* */ [In, Out] ref int pcbData);\n\n        [DllImport(Crypt32Dll, CharSet = CharSet.Auto, SetLastError = true)]\n        private static extern bool CryptMsgGetParam(\n            /* HCRYPTMSG */ [In] IntPtr hCryptMsg,\n            /* DWORD */ [In] int dwParamType,\n            /* DWORD */ [In] int dwIndex,\n            /* void* */ [In, Out] byte[] pvData,\n            /* DWORD* */ [In, Out] ref int pcbData);\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/CertificateStoreServiceStub.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class CertificateStoreServiceStub : ISignatureAlgorithmProvider, ICertificateProvider, IDisposable\n    {\n        private RSA? _rsa;\n        private X509Certificate2? _certificate;\n\n        public void Dispose()\n        {\n            _rsa?.Dispose();\n            _certificate?.Dispose();\n\n            GC.SuppressFinalize(this);\n        }\n\n        public Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken)\n        {\n            return Task.FromResult(new X509Certificate2(_certificate!));\n        }\n\n        public Task<RSA> GetRsaAsync(CancellationToken cancellationToken)\n        {\n            RSAParameters parameters = _rsa!.ExportParameters(includePrivateParameters: true);\n            RSA rsa = RSA.Create(parameters);\n\n            return Task.FromResult(rsa);\n        }\n\n        public void Initialize(string certificateFingerprint, string? cryptoServiceProvider, string? privateKeyContainer, string? privateMachineKeyContainer)\n        {\n            _rsa = RSA.Create(keySizeInBits: 4096);\n\n            // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n            CertificateRequest request = new(\"CN=test\", _rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            _certificate = request.CreateSelfSigned(now.AddMinutes(-5), now.AddMinutes(10));\n        }\n\n        public bool IsInitialized()\n        {\n            return _certificate != null && _rsa != null;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/ContainerProviderStub.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class ContainerProviderStub : IContainerProvider\n    {\n        private readonly ContainerProvider _containerProvider;\n\n        internal IEnumerable<ContainerSpy> Containers { get; set; } = Enumerable.Empty<ContainerSpy>();\n\n        internal ContainerProviderStub()\n        {\n            _containerProvider = new ContainerProvider(\n                Mock.Of<ICertificateProvider>(),\n                Mock.Of<IDirectoryService>(),\n                Mock.Of<IFileMatcher>(),\n                Mock.Of<IMakeAppxCli>(),\n                Mock.Of<ILogger<IContainerProvider>>());\n        }\n\n        public bool IsAppxBundleContainer(FileInfo file)\n        {\n            return _containerProvider.IsAppxBundleContainer(file);\n        }\n\n        public bool IsAppxContainer(FileInfo file)\n        {\n            return _containerProvider.IsAppxContainer(file);\n        }\n\n        public bool IsNuGetContainer(FileInfo file)\n        {\n            return _containerProvider.IsNuGetContainer(file);\n        }\n\n        public bool IsZipContainer(FileInfo file)\n        {\n            return _containerProvider.IsZipContainer(file);\n        }\n\n        public IContainer? GetContainer(FileInfo file)\n        {\n            ArgumentNullException.ThrowIfNull(file, nameof(file));\n\n            foreach (ContainerSpy container in Containers)\n            {\n                if (FileInfoComparer.Instance.Equals(container.File, file))\n                {\n                    return container;\n                }\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/ContainerSpy.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.FileSystemGlobbing;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class ContainerSpy : IContainer\n    {\n        private readonly FileMatcher _fileMatcher = new();\n\n        internal ushort Dispose_CallCount { get; private set; }\n        internal FileInfo File { get; }\n        internal HashSet<FileInfo> Files { get; } = new(FileInfoComparer.Instance);\n        internal ushort GetFiles_CallCount { get; private set; }\n        internal ushort GetFilesWithMatcher_CallCount { get; private set; }\n        internal ushort OpenAsync_CallCount { get; private set; }\n        internal ushort SaveAsync_CallCount { get; private set; }\n\n        internal ContainerSpy(FileInfo file)\n        {\n            File = file;\n        }\n\n        public void Dispose()\n        {\n            ++Dispose_CallCount;\n        }\n\n        public IEnumerable<FileInfo> GetFiles()\n        {\n            ++GetFiles_CallCount;\n\n            return Files;\n        }\n\n        public IEnumerable<FileInfo> GetFiles(Matcher matcher)\n        {\n            ++GetFilesWithMatcher_CallCount;\n\n            List<string> inMemoryFiles = Files.Select(file => file.FullName).ToList();\n            InMemoryDirectoryInfo directoryInfo = new(File.DirectoryName!, inMemoryFiles);\n\n            return _fileMatcher.EnumerateMatches(directoryInfo, matcher);\n        }\n\n        public ValueTask OpenAsync()\n        {\n            ++OpenAsync_CallCount;\n\n            return ValueTask.CompletedTask;\n        }\n\n        public ValueTask SaveAsync()\n        {\n            ++SaveAsync_CallCount;\n\n            return ValueTask.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/DirectoryServiceStub.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class DirectoryServiceStub : IDirectoryService\n    {\n        private readonly List<DirectoryInfo> _directories;\n\n        internal IReadOnlyList<DirectoryInfo> Directories { get; }\n\n        internal DirectoryServiceStub()\n        {\n            Directories = _directories = new List<DirectoryInfo>();\n        }\n\n        public DirectoryInfo CreateTemporaryDirectory()\n        {\n            DirectoryInfo directory = new(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n\n            directory.Create();\n\n            _directories.Add(directory);\n\n            return directory;\n        }\n\n        public void Delete(DirectoryInfo directory)\n        {\n            directory.Refresh();\n\n            if (directory.Exists)\n            {\n                directory.Delete(recursive: true);\n            }\n        }\n\n        public void Dispose()\n        {\n            foreach (DirectoryInfo directory in _directories)\n            {\n                Delete(directory);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/FileMetadataServiceStub.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class FileMetadataServiceStub : IFileMetadataService\n    {\n        internal List<FileInfo> PortableExecutableFiles { get; } = new();\n\n        public bool IsPortableExecutable(FileInfo file)\n        {\n            return PortableExecutableFiles.Contains(file, FileInfoComparer.Instance);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/KeyVaultServiceStub.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class KeyVaultServiceStub : ISignatureAlgorithmProvider, ICertificateProvider, IDisposable\n    {\n        private RSA? _rsa;\n        private X509Certificate2? _certificate;\n\n        internal KeyVaultServiceStub()\n        {\n            _rsa = RSA.Create(keySizeInBits: 4096);\n\n            // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n            CertificateRequest request = new(\"CN=test\", _rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            _certificate = request.CreateSelfSigned(now.AddMinutes(-5), now.AddMinutes(10));\n        }\n\n        public void Dispose()\n        {\n            _rsa?.Dispose();\n            _certificate?.Dispose();\n\n            GC.SuppressFinalize(this);\n        }\n\n        public Task<X509Certificate2> GetCertificateAsync(CancellationToken cancellationToken = default)\n        {\n            return Task.FromResult(new X509Certificate2(_certificate!));\n        }\n\n        public Task<RSA> GetRsaAsync(CancellationToken cancellationToken = default)\n        {\n            RSAParameters parameters = _rsa!.ExportParameters(includePrivateParameters: true);\n            RSA rsa = RSA.Create(parameters);\n\n            return Task.FromResult(rsa);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/AiaResponder.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class AiaResponder : HttpResponder\n    {\n        private readonly CertificateAuthority _certificateAuthority;\n        private readonly TimeSpan? _responseDelay;\n\n        public override Uri Url { get; }\n\n        internal AiaResponder(\n            CertificateAuthority certificateAuthority,\n            TimeSpan? responseDelay = null)\n        {\n            ArgumentNullException.ThrowIfNull(certificateAuthority, nameof(certificateAuthority));\n\n            _certificateAuthority = certificateAuthority;\n            _responseDelay = responseDelay;\n\n            if (certificateAuthority.AiaHttpUri is null)\n            {\n                throw new ArgumentException(message: null, nameof(certificateAuthority));\n            }\n\n            Url = new Uri(certificateAuthority.AiaHttpUri, UriKind.Absolute);\n        }\n\n        public override async Task RespondAsync(HttpContext context)\n        {\n            ArgumentNullException.ThrowIfNull(context, nameof(context));\n\n            if (_responseDelay.HasValue)\n            {\n                Trace.WriteLine($\"Delaying response by {_responseDelay.Value}.\");\n\n                await Task.Delay(_responseDelay.Value);\n            }\n\n            byte[] certData = _certificateAuthority.GetCertData();\n\n            context.Response.StatusCode = 200;\n            context.Response.ContentType = \"application/pkix-cert\";\n\n            await context.Response.Body.WriteAsync(certData);\n\n            Trace.WriteLine($\"[AIA]  Responded with {certData.Length}-byte certificate from {_certificateAuthority.SubjectName}.\");\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/AlgorithmIdentifier.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 3280 (https://tools.ietf.org/html/rfc3280#section-4.1.1.2):\n\n            AlgorithmIdentifier ::= SEQUENCE {\n                algorithm               OBJECT IDENTIFIER,\n                parameters              ANY DEFINED BY algorithm OPTIONAL\n            }\n\t*/\n    internal sealed class AlgorithmIdentifier\n    {\n        internal Oid Algorithm { get; }\n        internal ReadOnlyMemory<byte>? Parameters { get; }\n\n        internal AlgorithmIdentifier(Oid algorithm)\n        {\n            ArgumentNullException.ThrowIfNull(algorithm, nameof(algorithm));\n\n            Algorithm = algorithm;\n        }\n\n        internal static AlgorithmIdentifier Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader algIdReader = reader.ReadSequence();\n            Oid algorithm = new(algIdReader.ReadObjectIdentifier());\n\n            // For all algorithms we currently support, parameter must be null.\n            // However, presence of a DER encoded NULL value is optional.\n            if (algIdReader.HasData)\n            {\n                algIdReader.ReadNull();\n            }\n\n            algIdReader.ThrowIfNotEmpty();\n\n            return new AlgorithmIdentifier(algorithm);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(Algorithm.Value!);\n\n                if (Parameters.HasValue)\n                {\n                    writer.WriteEncodedValue(Parameters.Value.Span);\n                }\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/AttributeUtility.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    internal static class AttributeUtility\n    {\n        /// <summary>\n        /// Create a signing-certificate-v2 from a certificate.\n        /// </summary>\n        /// <param name=\"certificate\">The signing certificate.</param>\n        /// <param name=\"hashAlgorithm\">The hash algorithm for the signing-certificate-v2 attribute.</param>\n        internal static CryptographicAttributeObject CreateSigningCertificateV2Attribute(\n            X509Certificate2 certificate,\n            HashAlgorithmName hashAlgorithm)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            SigningCertificateV2 signingCertificateV2 = SigningCertificateV2.Create(certificate, hashAlgorithm);\n            ReadOnlyMemory<byte> bytes = signingCertificateV2.Encode();\n\n            AsnEncodedData data = new(Oids.SigningCertificateV2, bytes.Span);\n\n            return new CryptographicAttributeObject(\n                Oids.SigningCertificateV2,\n                new AsnEncodedDataCollection(data));\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CertificateAuthority.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    // This class represents only a portion of what is required to be a proper Certificate Authority.\n    //\n    // Please do not use it as the basis for any real Public/Private Key Infrastructure (PKI) system\n    // without understanding all of the portions of proper CA management that you're skipping.\n    //\n    // At minimum, read the current baseline requirements of the CA/Browser Forum.\n\n    [Flags]\n    internal enum PkiOptions\n    {\n        None = 0,\n\n        IssuerRevocationViaCrl = 1 << 0,\n        IssuerRevocationViaOcsp = 1 << 1,\n        EndEntityRevocationViaCrl = 1 << 2,\n        EndEntityRevocationViaOcsp = 1 << 3,\n\n        CrlEverywhere = IssuerRevocationViaCrl | EndEntityRevocationViaCrl,\n        OcspEverywhere = IssuerRevocationViaOcsp | EndEntityRevocationViaOcsp,\n        AllIssuerRevocation = IssuerRevocationViaCrl | IssuerRevocationViaOcsp,\n        AllEndEntityRevocation = EndEntityRevocationViaCrl | EndEntityRevocationViaOcsp,\n        AllRevocation = CrlEverywhere | OcspEverywhere,\n\n        IssuerAuthorityHasDesignatedOcspResponder = 1 << 16,\n        RootAuthorityHasDesignatedOcspResponder = 1 << 17,\n        NoIssuerCertDistributionUri = 1 << 18,\n        NoRootCertDistributionUri = 1 << 18,\n    }\n\n    internal sealed class CertificateAuthority : IDisposable\n    {\n        private static readonly Asn1Tag s_context0 = new(TagClass.ContextSpecific, 0);\n        private static readonly Asn1Tag s_context1 = new(TagClass.ContextSpecific, 1);\n        private static readonly Asn1Tag s_context2 = new(TagClass.ContextSpecific, 2);\n        private static readonly Asn1Tag s_context4 = new(TagClass.ContextSpecific, 4);\n\n        private static readonly X500DistinguishedName s_nonParticipatingName =\n            new(\"CN=The Ghost in the Machine\");\n\n        private static readonly X509BasicConstraintsExtension s_eeConstraints =\n            new(false, false, 0, false);\n\n        private static readonly X509KeyUsageExtension s_caKeyUsage =\n            new(\n                X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign,\n                critical: false);\n\n        private static readonly X509KeyUsageExtension s_eeKeyUsage =\n            new(\n                X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment,\n                critical: false);\n\n        private static readonly X509EnhancedKeyUsageExtension s_ocspResponderEku =\n            new(\n                new OidCollection\n                {\n                    new Oid(\"1.3.6.1.5.5.7.3.9\", null),\n                },\n                critical: false);\n\n        private static readonly X509EnhancedKeyUsageExtension s_tlsClientEku =\n            new(\n                new OidCollection\n                {\n                    new Oid(\"1.3.6.1.5.5.7.3.2\", null)\n                },\n                critical: false);\n\n        private static readonly X509EnhancedKeyUsageExtension s_codeSigningEku =\n            new(\n                new OidCollection\n                {\n                    Oids.CodeSigningEku\n                },\n                critical: false);\n\n        private static readonly X509Extension s_testCertificate =\n            new(Oids.Test, rawData: Array.Empty<byte>(), critical: false);\n\n        private X509Certificate2 _cert;\n        private byte[]? _certData;\n        private X509Extension? _cdpExtension;\n        private X509Extension? _aiaExtension;\n        private X509Extension? _akidExtension;\n\n        private List<(byte[], DateTimeOffset)>? _revocationList;\n        private byte[]? _crl;\n        private int _crlNumber;\n        private DateTimeOffset _crlExpiry;\n        private X509Certificate2? _ocspResponder;\n        private byte[]? _dnHash;\n        private byte[]? _keyHash;\n        private List<IDisposable> _disposables;\n\n        internal string? AiaHttpUri { get; }\n        internal string? CdpUri { get; }\n        internal string? OcspUri { get; }\n\n        internal bool CorruptRevocationSignature { get; set; }\n        internal DateTimeOffset? RevocationExpiration { get; set; }\n        internal bool CorruptRevocationIssuerName { get; set; }\n        internal bool OmitNextUpdateInCrl { get; set; }\n\n        // All keys created in this method only live for a few seconds (at most),\n        // and never communicate out of process.\n        const int DefaultKeySize = 3072;\n\n        internal CertificateAuthority(\n            X509Certificate2 cert,\n            string? aiaHttpUrl,\n            string? cdpUrl,\n            string? ocspUrl)\n        {\n            _cert = cert;\n            AiaHttpUri = aiaHttpUrl;\n            CdpUri = cdpUrl;\n            OcspUri = ocspUrl;\n\n            _disposables = new List<IDisposable>();\n        }\n\n        public void Dispose()\n        {\n            _cert.Dispose();\n        }\n\n        internal string SubjectName => _cert.Subject;\n        internal bool HasOcspDelegation => _ocspResponder != null;\n        internal string OcspResponderSubjectName => (_ocspResponder ?? _cert).Subject;\n\n        internal X509Certificate2 CloneIssuerCert()\n        {\n            return new X509Certificate2(_cert.RawData);\n        }\n\n        internal void Revoke(X509Certificate2 certificate, DateTimeOffset revocationTime)\n        {\n            if (!certificate.IssuerName.RawData.SequenceEqual(_cert.SubjectName.RawData))\n            {\n                throw new ArgumentException(\"Certificate was not from this issuer\", nameof(certificate));\n            }\n\n            if (_revocationList == null)\n            {\n                _revocationList = new List<(byte[], DateTimeOffset)>();\n            }\n\n            byte[] serial = certificate.GetSerialNumber();\n            Array.Reverse(serial);\n            _revocationList.Add((serial, revocationTime));\n            _crl = null;\n        }\n\n        internal X509Certificate2 CreateSubordinateCA(\n            string subject,\n            RSA publicKey,\n            int? depthLimit = null)\n        {\n            return CreateCertificate(\n                subject,\n                publicKey,\n                TimeSpan.FromMinutes(1),\n                new X509ExtensionCollection() {\n                    new X509BasicConstraintsExtension(\n                        certificateAuthority: true,\n                        depthLimit.HasValue,\n                        depthLimit.GetValueOrDefault(),\n                        critical: true),\n                    s_caKeyUsage,\n                    s_testCertificate});\n        }\n\n        internal X509Certificate2 CreateEndEntity(\n            string subject,\n            RSA publicKey,\n            X509ExtensionCollection extensions,\n            DateTimeOffset? notAfter = null)\n        {\n            return CreateCertificate(\n                subject,\n                publicKey,\n                TimeSpan.FromSeconds(2),\n                extensions,\n                notAfter);\n        }\n\n        internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey)\n        {\n            return CreateCertificate(\n                subject,\n                publicKey,\n                TimeSpan.FromSeconds(1),\n                new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_ocspResponderEku },\n                ocspResponder: true);\n        }\n\n        internal X509Certificate2 Create(CertificateRequest request, DateTimeOffset? notAfter = null)\n        {\n            ArgumentNullException.ThrowIfNull(request, nameof(request));\n\n            return CreateCertificate(\n                request,\n                TimeSpan.FromSeconds(2),\n                new X509ExtensionCollection(),\n                notAfter,\n                ocspResponder: false);\n        }\n\n        internal void RebuildRootWithRevocation()\n        {\n            if (_cdpExtension == null && CdpUri != null)\n            {\n                _cdpExtension = CreateCdpExtension(CdpUri);\n            }\n\n            if (_aiaExtension == null && (OcspUri != null || AiaHttpUri != null))\n            {\n                _aiaExtension = CreateAiaExtension(AiaHttpUri, OcspUri);\n            }\n\n            RebuildRootWithRevocation(_cdpExtension, _aiaExtension);\n        }\n\n        private void RebuildRootWithRevocation(X509Extension? cdpExtension, X509Extension? aiaExtension)\n        {\n            X500DistinguishedName subjectName = _cert.SubjectName;\n\n            if (!subjectName.RawData.SequenceEqual(_cert.IssuerName.RawData))\n            {\n                throw new InvalidOperationException();\n            }\n\n            CertificateRequest req = new(subjectName, _cert.PublicKey, HashAlgorithmName.SHA256);\n\n            foreach (X509Extension ext in _cert.Extensions)\n            {\n                req.CertificateExtensions.Add(ext);\n            }\n\n            if (cdpExtension is not null)\n            {\n                req.CertificateExtensions.Add(cdpExtension);\n            }\n\n            if (aiaExtension is not null)\n            {\n                req.CertificateExtensions.Add(aiaExtension);\n            }\n\n            byte[] serial = _cert.GetSerialNumber();\n            Array.Reverse(serial);\n\n            X509Certificate2 dispose = _cert;\n\n            using (dispose)\n            using (RSA rsa = _cert.GetRSAPrivateKey()!)\n            using (X509Certificate2 tmp = req.Create(\n                subjectName,\n                // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1),\n                new DateTimeOffset(_cert.NotBefore),\n                new DateTimeOffset(_cert.NotAfter),\n                serial))\n            {\n                _cert = tmp.CopyWithPrivateKey(rsa);\n            }\n        }\n\n        private X509Certificate2 CreateCertificate(\n            string subject,\n            RSA publicKey,\n            TimeSpan nestingBuffer,\n            X509ExtensionCollection extensions,\n            DateTimeOffset? notAfter = null,\n            bool ocspResponder = false)\n        {\n            CertificateRequest request = new(\n                subject,\n                publicKey,\n                HashAlgorithmName.SHA256,\n                // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                RSASignaturePadding.Pkcs1);\n\n            return CreateCertificate(request, nestingBuffer, extensions, notAfter, ocspResponder);\n        }\n\n        private X509Certificate2 CreateCertificate(\n            CertificateRequest request,\n            TimeSpan nestingBuffer,\n            X509ExtensionCollection extensions,\n            DateTimeOffset? notAfter = null,\n            bool ocspResponder = false)\n        {\n            if (_cdpExtension == null && CdpUri != null)\n            {\n                _cdpExtension = CreateCdpExtension(CdpUri);\n            }\n\n            if (_aiaExtension == null && (OcspUri != null || AiaHttpUri != null))\n            {\n                _aiaExtension = CreateAiaExtension(AiaHttpUri, OcspUri);\n            }\n\n            if (_akidExtension == null)\n            {\n                _akidExtension = CreateAkidExtension();\n            }\n\n            foreach (X509Extension extension in extensions)\n            {\n                request.CertificateExtensions.Add(extension);\n            }\n\n            // Windows does not accept OCSP Responder certificates which have\n            // a CDP extension, or an AIA extension with an OCSP endpoint.\n            if (!ocspResponder)\n            {\n                if (_cdpExtension is not null)\n                {\n                    request.CertificateExtensions.Add(_cdpExtension);\n                }\n\n                if (_aiaExtension is not null)\n                {\n                    request.CertificateExtensions.Add(_aiaExtension);\n                }\n            }\n\n            request.CertificateExtensions.Add(_akidExtension);\n            request.CertificateExtensions.Add(\n                new X509SubjectKeyIdentifierExtension(request.PublicKey, false));\n\n            byte[] serial = GenerateSerialNumber();\n\n            DateTimeOffset notBefore = _cert.NotBefore.Add(nestingBuffer);\n\n            notAfter ??= _cert.NotAfter.Subtract(nestingBuffer);\n\n            return request.Create(\n                _cert,\n                notBefore,\n                notAfter.Value,\n                serial);\n        }\n\n        internal byte[] GetCertData()\n        {\n            return (_certData ??= _cert.RawData);\n        }\n\n        internal byte[] GetCrl()\n        {\n            byte[]? crl = _crl;\n            DateTimeOffset now = DateTimeOffset.UtcNow;\n\n            if (crl != null && now < _crlExpiry)\n            {\n                return crl;\n            }\n\n            DateTimeOffset newExpiry = now.AddSeconds(2);\n\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(\"1.2.840.113549.1.1.11\");\n                writer.WriteNull();\n            }\n\n            byte[] signatureAlgId = writer.Encode();\n            writer.Reset();\n\n            // TBSCertList\n            using (writer.PushSequence())\n            {\n                // version v2(1)\n                writer.WriteInteger(1);\n\n                // signature (AlgorithmIdentifier)\n                writer.WriteEncodedValue(signatureAlgId);\n\n                // issuer\n                if (CorruptRevocationIssuerName)\n                {\n                    writer.WriteEncodedValue(s_nonParticipatingName.RawData);\n                }\n                else\n                {\n                    writer.WriteEncodedValue(_cert.SubjectName.RawData);\n                }\n\n                if (RevocationExpiration.HasValue)\n                {\n                    // thisUpdate\n                    writer.WriteUtcTime(_cert.NotBefore);\n\n                    // nextUpdate\n                    if (!OmitNextUpdateInCrl)\n                    {\n                        writer.WriteUtcTime(RevocationExpiration.Value);\n                    }\n                }\n                else\n                {\n                    // thisUpdate\n                    writer.WriteUtcTime(now);\n\n                    // nextUpdate\n                    if (!OmitNextUpdateInCrl)\n                    {\n                        writer.WriteUtcTime(newExpiry);\n                    }\n                }\n\n                // revokedCertificates (don't write down if empty)\n                if (_revocationList?.Count > 0)\n                {\n                    // SEQUENCE OF\n                    using (writer.PushSequence())\n                    {\n                        foreach ((byte[] serial, DateTimeOffset when) in _revocationList)\n                        {\n                            // Anonymous CRL Entry type\n                            using (writer.PushSequence())\n                            {\n                                writer.WriteInteger(serial);\n                                writer.WriteUtcTime(when);\n                            }\n                        }\n                    }\n                }\n\n                // extensions [0] EXPLICIT Extensions\n                using (writer.PushSequence(s_context0))\n                {\n                    // Extensions (SEQUENCE OF)\n                    using (writer.PushSequence())\n                    {\n                        if (_akidExtension == null)\n                        {\n                            _akidExtension = CreateAkidExtension();\n                        }\n\n                        // Authority Key Identifier Extension\n                        using (writer.PushSequence())\n                        {\n                            writer.WriteObjectIdentifier(_akidExtension.Oid!.Value!);\n\n                            if (_akidExtension.Critical)\n                            {\n                                writer.WriteBoolean(true);\n                            }\n\n                            writer.WriteOctetString(_akidExtension.RawData);\n                        }\n\n                        // CRL Number Extension\n                        using (writer.PushSequence())\n                        {\n                            writer.WriteObjectIdentifier(\"2.5.29.20\");\n\n                            using (writer.PushOctetString())\n                            {\n                                writer.WriteInteger(_crlNumber);\n                            }\n                        }\n                    }\n                }\n            }\n\n            byte[] tbsCertList = writer.Encode();\n            writer.Reset();\n\n            byte[] signature;\n\n            using (RSA key = _cert.GetRSAPrivateKey()!)\n            {\n                // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                signature = key.SignData(tbsCertList, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n\n                if (CorruptRevocationSignature)\n                {\n                    signature[5] ^= 0xFF;\n                }\n            }\n\n            // CertificateList\n            using (writer.PushSequence())\n            {\n                writer.WriteEncodedValue(tbsCertList);\n                writer.WriteEncodedValue(signatureAlgId);\n                writer.WriteBitString(signature);\n            }\n\n            _crl = writer.Encode();\n\n            _crlExpiry = newExpiry;\n            _crlNumber++;\n            return _crl;\n        }\n\n        internal void DesignateOcspResponder(X509Certificate2 responder)\n        {\n            _ocspResponder = responder;\n        }\n\n        internal byte[] BuildOcspResponse(\n            ReadOnlyMemory<byte> certId,\n            ReadOnlyMemory<byte> nonceExtension)\n        {\n            DateTimeOffset now = DateTimeOffset.UtcNow;\n\n            DateTimeOffset revokedTime = default;\n            CertStatus status = CheckRevocation(certId, ref revokedTime);\n            X509Certificate2 responder = (_ocspResponder ?? _cert);\n\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            /*\n   ResponseData ::= SEQUENCE {\n      version              [0] EXPLICIT Version DEFAULT v1,\n      responderID              ResponderID,\n      producedAt               GeneralizedTime,\n      responses                SEQUENCE OF SingleResponse,\n      responseExtensions   [1] EXPLICIT Extensions OPTIONAL }\n                 */\n            using (writer.PushSequence())\n            {\n                // Skip version (v1)\n\n                /*\nResponderID ::= CHOICE {\n  byName               [1] Name,\n  byKey                [2] KeyHash }\n                 */\n\n                using (writer.PushSequence(s_context1))\n                {\n                    if (CorruptRevocationIssuerName)\n                    {\n                        writer.WriteEncodedValue(s_nonParticipatingName.RawData);\n                    }\n                    else\n                    {\n                        writer.WriteEncodedValue(responder.SubjectName.RawData);\n                    }\n                }\n\n                writer.WriteGeneralizedTime(now, omitFractionalSeconds: true);\n\n                using (writer.PushSequence())\n                {\n                    /*\nSingleResponse ::= SEQUENCE {\n  certID                       CertID,\n  certStatus                   CertStatus,\n  thisUpdate                   GeneralizedTime,\n  nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,\n  singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }\n                     */\n                    using (writer.PushSequence())\n                    {\n                        writer.WriteEncodedValue(certId.Span);\n\n                        if (status == CertStatus.OK)\n                        {\n                            writer.WriteNull(s_context0);\n                        }\n                        else if (status == CertStatus.Revoked)\n                        {\n                            // Android does not support all precisions for seconds - just omit fractional seconds for testing on Android\n                            writer.PushSequence(s_context1);\n                            writer.WriteGeneralizedTime(revokedTime, omitFractionalSeconds: OperatingSystem.IsAndroid());\n                            writer.PopSequence(s_context1);\n                        }\n                        else\n                        {\n                            Assert.Equal(CertStatus.Unknown, status);\n                            writer.WriteNull(s_context2);\n                        }\n\n                        if (RevocationExpiration.HasValue)\n                        {\n                            writer.WriteGeneralizedTime(\n                                _cert.NotBefore,\n                                omitFractionalSeconds: true);\n\n                            using (writer.PushSequence(s_context0))\n                            {\n                                writer.WriteGeneralizedTime(\n                                    RevocationExpiration.Value,\n                                    omitFractionalSeconds: true);\n                            }\n                        }\n                        else\n                        {\n                            writer.WriteGeneralizedTime(now, omitFractionalSeconds: true);\n                        }\n                    }\n                }\n\n                if (!nonceExtension.IsEmpty)\n                {\n                    using (writer.PushSequence(s_context1))\n                    using (writer.PushSequence())\n                    {\n                        writer.WriteEncodedValue(nonceExtension.Span);\n                    }\n                }\n            }\n\n            byte[] tbsResponseData = writer.Encode();\n            writer.Reset();\n\n            /*\n                BasicOCSPResponse       ::= SEQUENCE {\n  tbsResponseData      ResponseData,\n  signatureAlgorithm   AlgorithmIdentifier,\n  signature            BIT STRING,\n  certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }\n             */\n            using (writer.PushSequence())\n            {\n                writer.WriteEncodedValue(tbsResponseData);\n\n                using (writer.PushSequence())\n                {\n                    writer.WriteObjectIdentifier(\"1.2.840.113549.1.1.11\");\n                    writer.WriteNull();\n                }\n\n                using (RSA rsa = responder.GetRSAPrivateKey()!)\n                {\n                    byte[] signature = rsa.SignData(\n                        tbsResponseData,\n                        HashAlgorithmName.SHA256,\n                        // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                        RSASignaturePadding.Pkcs1);\n\n                    if (CorruptRevocationSignature)\n                    {\n                        signature[5] ^= 0xFF;\n                    }\n\n                    writer.WriteBitString(signature);\n                }\n\n                if (_ocspResponder != null)\n                {\n                    using (writer.PushSequence(s_context0))\n                    using (writer.PushSequence())\n                    {\n                        writer.WriteEncodedValue(_ocspResponder.RawData);\n                        writer.PopSequence();\n                    }\n                }\n            }\n\n            byte[] responseBytes = writer.Encode();\n            writer.Reset();\n\n            using (writer.PushSequence())\n            {\n                writer.WriteEnumeratedValue(OcspResponseStatus.Successful);\n\n                using (writer.PushSequence(s_context0))\n                using (writer.PushSequence())\n                {\n                    writer.WriteObjectIdentifier(\"1.3.6.1.5.5.7.48.1.1\");\n                    writer.WriteOctetString(responseBytes);\n                }\n            }\n\n            return writer.Encode();\n        }\n\n        private CertStatus CheckRevocation(ReadOnlyMemory<byte> certId, ref DateTimeOffset revokedTime)\n        {\n            AsnReader reader = new(certId, AsnEncodingRules.DER);\n            AsnReader idReader = reader.ReadSequence();\n            reader.ThrowIfNotEmpty();\n\n            AsnReader algIdReader = idReader.ReadSequence();\n            Oid hashAlgorithmOid = new(algIdReader.ReadObjectIdentifier());\n\n            if (algIdReader.HasData)\n            {\n                algIdReader.ReadNull();\n                algIdReader.ThrowIfNotEmpty();\n            }\n\n            if (hashAlgorithmOid.IsEqualTo(Oids.Sha1))\n            {\n                // SHA-1 is obsolete.  We'll rely on serial number only for matching.\n            }\n            else if (IsSupportedHashAlgorithm(hashAlgorithmOid))\n            {\n                if (_dnHash is null || _keyHash is null)\n                {\n                    using (HashAlgorithm hashAlgorithm = CreateHashAlgorithm(hashAlgorithmOid))\n                    {\n                        _dnHash = hashAlgorithm.ComputeHash(_cert.SubjectName.RawData);\n                        _keyHash = hashAlgorithm.ComputeHash(_cert.GetPublicKey());\n                    }\n                }\n\n                if (!idReader.TryReadPrimitiveOctetString(out ReadOnlyMemory<byte> reqDn))\n                {\n                    idReader.ThrowIfNotEmpty();\n                }\n\n                if (!reqDn.Span.SequenceEqual(_dnHash))\n                {\n                    return CertStatus.Unknown;\n                }\n\n                if (!idReader.TryReadPrimitiveOctetString(out ReadOnlyMemory<byte> reqKeyHash))\n                {\n                    idReader.ThrowIfNotEmpty();\n                }\n\n                if (!reqKeyHash.Span.SequenceEqual(_keyHash))\n                {\n                    return CertStatus.Unknown;\n                }\n            }\n            else\n            {\n                return CertStatus.Unknown;\n            }\n\n            ReadOnlyMemory<byte> reqSerial = idReader.ReadIntegerBytes();\n            idReader.ThrowIfNotEmpty();\n\n            if (_revocationList == null)\n            {\n                return CertStatus.OK;\n            }\n\n            ReadOnlySpan<byte> reqSerialSpan = reqSerial.Span;\n\n            foreach ((byte[] serial, DateTimeOffset time) in _revocationList)\n            {\n                if (reqSerialSpan.SequenceEqual(serial))\n                {\n                    revokedTime = time;\n                    return CertStatus.Revoked;\n                }\n            }\n\n            return CertStatus.OK;\n        }\n\n        private static X509Extension CreateAiaExtension(string? certLocation, string? ocspStem)\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            // AuthorityInfoAccessSyntax (SEQUENCE OF)\n            using (writer.PushSequence())\n            {\n                if (!string.IsNullOrEmpty(ocspStem))\n                {\n                    // AccessDescription for id-ad-ocsp\n                    using (writer.PushSequence())\n                    {\n                        writer.WriteObjectIdentifier(\"1.3.6.1.5.5.7.48.1\");\n\n                        writer.WriteCharacterString(\n                            UniversalTagNumber.IA5String,\n                            ocspStem,\n                            new Asn1Tag(TagClass.ContextSpecific, 6));\n                    }\n                }\n\n                if (!string.IsNullOrEmpty(certLocation))\n                {\n                    // AccessDescription for id-ad-caIssuers\n                    using (writer.PushSequence())\n                    {\n                        writer.WriteObjectIdentifier(\"1.3.6.1.5.5.7.48.2\");\n\n                        writer.WriteCharacterString(\n                            UniversalTagNumber.IA5String,\n                            certLocation,\n                            new Asn1Tag(TagClass.ContextSpecific, 6));\n                    }\n                }\n            }\n\n            return new X509Extension(\"1.3.6.1.5.5.7.1.1\", writer.Encode(), false);\n        }\n\n        private static X509Extension CreateCdpExtension(string cdp)\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            // SEQUENCE OF\n            using (writer.PushSequence())\n            {\n                // DistributionPoint\n                using (writer.PushSequence())\n                {\n                    // Because DistributionPointName is a CHOICE type this tag is explicit.\n                    // (ITU-T REC X.680-201508 C.3.2.2(g)(3rd bullet))\n                    // distributionPoint [0] DistributionPointName\n                    using (writer.PushSequence(s_context0))\n                    {\n                        // [0] DistributionPointName (GeneralNames (SEQUENCE OF))\n                        using (writer.PushSequence(s_context0))\n                        {\n                            // GeneralName ([6]  IA5String)\n                            writer.WriteCharacterString(\n                                UniversalTagNumber.IA5String,\n                                cdp,\n                                new Asn1Tag(TagClass.ContextSpecific, 6));\n                        }\n                    }\n                }\n            }\n\n            return new X509Extension(\"2.5.29.31\", writer.Encode(), false);\n        }\n\n        private X509Extension CreateAkidExtension()\n        {\n            X509SubjectKeyIdentifierExtension? skid =\n                _cert.Extensions.OfType<X509SubjectKeyIdentifierExtension>().SingleOrDefault();\n\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            // AuthorityKeyIdentifier\n            using (writer.PushSequence())\n            {\n                if (skid == null)\n                {\n                    // authorityCertIssuer [1] GeneralNames (SEQUENCE OF)\n                    using (writer.PushSequence(s_context1))\n                    {\n                        // directoryName [4] Name\n                        byte[] dn = _cert.SubjectName.RawData;\n\n                        if (s_context4.Encode(dn) != 1)\n                        {\n                            throw new InvalidOperationException();\n                        }\n\n                        writer.WriteEncodedValue(dn);\n                    }\n\n                    // authorityCertSerialNumber [2] CertificateSerialNumber (INTEGER)\n                    byte[] serial = _cert.GetSerialNumber();\n                    Array.Reverse(serial);\n                    writer.WriteInteger(serial, s_context2);\n                }\n                else\n                {\n                    // keyIdentifier [0] KeyIdentifier (OCTET STRING)\n                    AsnReader reader = new(skid.RawData, AsnEncodingRules.BER);\n                    ReadOnlyMemory<byte> contents;\n\n                    if (!reader.TryReadPrimitiveOctetString(out contents))\n                    {\n                        throw new InvalidOperationException();\n                    }\n\n                    reader.ThrowIfNotEmpty();\n                    writer.WriteOctetString(contents.Span, s_context0);\n                }\n            }\n\n            return new X509Extension(\"2.5.29.35\", writer.Encode(), false);\n        }\n\n        private enum OcspResponseStatus\n        {\n            Successful,\n        }\n\n        private enum CertStatus\n        {\n            Unknown,\n            OK,\n            Revoked,\n        }\n\n        internal static void BuildPrivatePki(\n            PkiOptions pkiOptions,\n            ITestServer server,\n            out CertificateAuthority rootAuthority,\n            out CertificateAuthority[] intermediateAuthorities,\n            out X509Certificate2 endEntityCert,\n            int intermediateAuthorityCount,\n            string? testName = null,\n            bool registerAuthorities = true,\n            bool pkiOptionsInSubject = false,\n            string? subjectName = null,\n            int keySize = DefaultKeySize,\n            X509ExtensionCollection? extensions = null)\n        {\n            bool rootDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoRootCertDistributionUri);\n            bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl);\n            bool issuerRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaOcsp);\n            bool issuerDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoIssuerCertDistributionUri);\n            bool endEntityRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaCrl);\n            bool endEntityRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaOcsp);\n\n            Assert.True(\n                issuerRevocationViaCrl || issuerRevocationViaOcsp ||\n                    endEntityRevocationViaCrl || endEntityRevocationViaOcsp,\n                \"At least one revocation mode is enabled\");\n\n            extensions ??= new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_codeSigningEku };\n\n            using (RSA rootKey = RSA.Create(keySize))\n            using (RSA eeKey = RSA.Create(keySize))\n            {\n                CertificateRequest rootReq = new(\n                    BuildSubject($\"{Constants.CommonNamePrefix} Root CA {Guid.NewGuid().ToString(\"P\")}\", testName, pkiOptions, pkiOptionsInSubject),\n                    rootKey,\n                    HashAlgorithmName.SHA256,\n                    // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                    RSASignaturePadding.Pkcs1);\n\n                X509BasicConstraintsExtension caConstraints =\n                    new(true, false, 0, true);\n\n                rootReq.CertificateExtensions.Add(caConstraints);\n                X509SubjectKeyIdentifierExtension rootSkid = new(rootReq.PublicKey, false);\n                rootReq.CertificateExtensions.Add(\n                    rootSkid);\n\n                DateTimeOffset start = DateTimeOffset.UtcNow;\n                DateTimeOffset end = start.AddMonths(3);\n\n                // Don't dispose this, it's being transferred to the CertificateAuthority\n                X509Certificate2 rootCert = rootReq.CreateSelfSigned(start.AddDays(-2), end.AddDays(2));\n                string UriPrefix = server.Url.AbsoluteUri;\n\n                string certUrl = $\"{UriPrefix}cert/{rootSkid.SubjectKeyIdentifier}.cer\";\n                string cdpUrl = $\"{UriPrefix}crl/{rootSkid.SubjectKeyIdentifier}.crl\";\n                string ocspUrl = $\"{UriPrefix}ocsp/{rootSkid.SubjectKeyIdentifier}\";\n\n                rootAuthority = new CertificateAuthority(\n                    rootCert,\n                    rootDistributionViaHttp ? certUrl : null,\n                    issuerRevocationViaCrl ? cdpUrl : null,\n                    issuerRevocationViaOcsp ? ocspUrl : null);\n\n                CertificateAuthority issuingAuthority = rootAuthority;\n                intermediateAuthorities = new CertificateAuthority[intermediateAuthorityCount];\n\n                for (int intermediateIndex = 0; intermediateIndex < intermediateAuthorityCount; intermediateIndex++)\n                {\n                    using RSA intermediateKey = RSA.Create(keySize);\n\n                    // Don't dispose this, it's being transferred to the CertificateAuthority\n                    X509Certificate2 intermedCert;\n\n                    {\n                        X509Certificate2 intermedPub = issuingAuthority.CreateSubordinateCA(\n                            BuildSubject($\"{Constants.CommonNamePrefix} Intermediate CA {intermediateIndex} {Guid.NewGuid().ToString(\"P\")}\", testName, pkiOptions, pkiOptionsInSubject),\n                            intermediateKey);\n                        intermedCert = intermedPub.CopyWithPrivateKey(intermediateKey);\n                        intermedPub.Dispose();\n                    }\n\n                    X509SubjectKeyIdentifierExtension intermedSkid =\n                        intermedCert.Extensions.OfType<X509SubjectKeyIdentifierExtension>().Single();\n\n                    certUrl = $\"{UriPrefix}cert/{intermedSkid.SubjectKeyIdentifier}.cer\";\n                    cdpUrl = $\"{UriPrefix}crl/{intermedSkid.SubjectKeyIdentifier}.crl\";\n                    ocspUrl = $\"{UriPrefix}ocsp/{intermedSkid.SubjectKeyIdentifier}\";\n\n                    CertificateAuthority intermediateAuthority = new(\n                        intermedCert,\n                        issuerDistributionViaHttp ? certUrl : null,\n                        endEntityRevocationViaCrl ? cdpUrl : null,\n                        endEntityRevocationViaOcsp ? ocspUrl : null);\n\n                    issuingAuthority = intermediateAuthority;\n                    intermediateAuthorities[intermediateIndex] = intermediateAuthority;\n                }\n\n                endEntityCert = issuingAuthority.CreateEndEntity(\n                    BuildSubject(subjectName ?? $\"{Constants.CommonNamePrefix} End Certificate {Guid.NewGuid().ToString(\"P\")}\", testName, pkiOptions, pkiOptionsInSubject),\n                    eeKey,\n                    extensions);\n\n                endEntityCert = endEntityCert.CopyWithPrivateKey(eeKey);\n            }\n\n            if (registerAuthorities)\n            {\n                rootAuthority._disposables.Add(server.RegisterResponder(new AiaResponder(rootAuthority)));\n                rootAuthority._disposables.Add(server.RegisterResponder(new CrlResponder(rootAuthority)));\n                rootAuthority._disposables.Add(server.RegisterResponder(new OcspResponder(rootAuthority)));\n\n                foreach (CertificateAuthority authority in intermediateAuthorities)\n                {\n                    authority._disposables.Add(server.RegisterResponder(new AiaResponder(authority)));\n                    authority._disposables.Add(server.RegisterResponder(new CrlResponder(authority)));\n                    authority._disposables.Add(server.RegisterResponder(new OcspResponder(authority)));\n                }\n            }\n        }\n\n        internal static void BuildPrivatePki(\n            PkiOptions pkiOptions,\n            ITestServer testServer,\n            out CertificateAuthority rootAuthority,\n            out CertificateAuthority intermediateAuthority,\n            out X509Certificate2 endEntityCert,\n            string? testName = null,\n            bool registerAuthorities = true,\n            bool pkiOptionsInSubject = false,\n            string? subjectName = null,\n            int keySize = DefaultKeySize,\n            X509ExtensionCollection? extensions = null)\n        {\n            BuildPrivatePki(\n                pkiOptions,\n                testServer,\n                out rootAuthority,\n                out CertificateAuthority[] intermediateAuthorities,\n                out endEntityCert,\n                intermediateAuthorityCount: 1,\n                testName: testName,\n                registerAuthorities: registerAuthorities,\n                pkiOptionsInSubject: pkiOptionsInSubject,\n                subjectName: subjectName,\n                keySize: keySize,\n                extensions: extensions);\n\n            intermediateAuthority = intermediateAuthorities.Single();\n        }\n\n        private static string BuildSubject(\n            string cn,\n            string? testName,\n            PkiOptions pkiOptions,\n            bool includePkiOptions)\n        {\n            if (includePkiOptions)\n            {\n                return $\"CN=\\\"{cn}\\\", O=\\\"{testName}\\\", OU=\\\"{pkiOptions}\\\"\";\n            }\n\n            return $\"CN=\\\"{cn}\\\", O=\\\"{testName}\\\"\";\n        }\n\n        private static bool IsSupportedHashAlgorithm(Oid oid)\n        {\n            return oid.IsEqualTo(Oids.Sha256)\n                || oid.IsEqualTo(Oids.Sha384)\n                || oid.IsEqualTo(Oids.Sha512);\n        }\n\n        private static HashAlgorithm CreateHashAlgorithm(Oid oid)\n        {\n            if (oid.IsEqualTo(Oids.Sha256))\n            {\n                return SHA256.Create();\n            }\n\n            if (oid.IsEqualTo(Oids.Sha384))\n            {\n                return SHA384.Create();\n            }\n\n            if (oid.IsEqualTo(Oids.Sha512))\n            {\n                return SHA512.Create();\n            }\n\n            throw new ArgumentException($\"Hash algorithm {oid.Value} is unsupported.\");\n        }\n\n        private static byte[] GenerateSerialNumber()\n        {\n            // See https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2\n            //\n            // A serial number MUST be:\n            //\n            //    * a non-negative integer\n            //    * unique for that CA\n            //    * <= 20 bytes\n            //    * big-endian encoded\n            //\n            // To enforce uniqueness, we'll use BigInteger.\n            //\n            // Endianness here is dictated by .NET API's not the CPU architecture running this code.\n            //\n            //    * BigInteger's constructor requires an array of bytes interpreted as an integer in little-endian order.\n            //    * CertificateRequest.Create(...) requires an array of bytes interpreted as an unsigned integer in big-endian order.\n            byte[] bytes = new byte[20];\n\n            RandomNumberGenerator.Fill(bytes);\n\n            // Treat the byte array as a big-endian integer.\n            // Ensure the number is non-negative by setting the highest bit of the first byte (big-endian) to 0.\n            bytes[0] &= 0x7F;\n\n            return bytes;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CertificateUtilities.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    internal static class CertificateUtilities\n    {\n        internal static RSA CreateKeyPair(int strength = 2048)\n        {\n            return RSA.Create(keySizeInBits: strength);\n        }\n\n        internal static X509Certificate2 GetCertificateWithPrivateKey(X509Certificate2 certificate, AsymmetricAlgorithm keyPair)\n        {\n            if (keyPair is RSA rsa)\n            {\n                return certificate.CopyWithPrivateKey(rsa);\n            }\n\n            if (keyPair is ECDsa ecdsa)\n            {\n                return certificate.CopyWithPrivateKey(ecdsa);\n            }\n\n            throw new ArgumentException(message: null, nameof(keyPair));\n        }\n\n        internal static ReadOnlyMemory<byte> Hash(this X509Certificate2 certificate, HashAlgorithmName hashAlgorithmName)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            using (HashAlgorithm hashAlgorithm = Create(hashAlgorithmName))\n            {\n                return hashAlgorithm.ComputeHash(certificate.RawData);\n            }\n        }\n\n        // It would seem that calling HashAlgorithm.Create(string) would be the simplest option,\n        // but it generates the following linker warning when trimming is enabled:\n        //      Trim analysis warning IL2026:\n        //      Microsoft.VisualStudio.Extensions.Signing.HashingExtensions.<HashAsync>d__1.MoveNext():\n        //      Using member 'System.Security.Cryptography.HashAlgorithm.Create(String)'\n        //      which has 'RequiresUnreferencedCodeAttribute' can break functionality\n        //      when trimming application code. The default algorithm implementations\n        //      might be removed, use strong type references like 'RSA.Create()' instead.\n        // Ignoring the warning and using HashAlgorithm.Create(string) anyway results in runtime\n        // error calling that method.\n        private static HashAlgorithm Create(HashAlgorithmName hashAlgorithmName)\n        {\n            if (hashAlgorithmName == HashAlgorithmName.SHA256)\n            {\n                return SHA256.Create();\n            }\n            else if (hashAlgorithmName == HashAlgorithmName.SHA384)\n            {\n                return SHA384.Create();\n            }\n            else if (hashAlgorithmName == HashAlgorithmName.SHA512)\n            {\n                return SHA512.Create();\n            }\n\n            throw new ArgumentException(message: null, nameof(hashAlgorithmName));\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CertificatesFixture.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    [CollectionDefinition(Name, DisableParallelization = true)]\n    public sealed class CertificatesFixture\n    {\n        private const string Name = nameof(CertificatesFixture);\n\n        private readonly CertificateAuthority _timestampRootCa;\n        private readonly CertificateAuthority _timestampIntermediateCa;\n        private readonly X509Certificate2 _timestampingRootCertificate;\n        private readonly X509Certificate2 _timestampingIntermediateCertificate;\n        private readonly TimestampService _timestampService;\n\n        internal Uri TimestampServiceUrl { get; }\n        internal X509Certificate TimestampServiceCertificate\n        {\n            get => _timestampService.Certificate;\n        }\n\n        public CertificatesFixture()\n        {\n            TestUtility.RemoveTestIntermediateCertificates();\n\n            ITestServer server = TestServerFixture.Instance;\n\n            CertificateAuthority.BuildPrivatePki(\n                PkiOptions.AllRevocation,\n                server,\n                out CertificateAuthority timestampRootCa,\n                out CertificateAuthority timestampIntermediateCa,\n                out X509Certificate2 timestampEndEntity,\n                testName: \"Test TSA\",\n                registerAuthorities: true);\n\n            timestampEndEntity.Dispose();\n\n            _timestampRootCa = timestampRootCa;\n            _timestampIntermediateCa = timestampIntermediateCa;\n            _timestampingRootCertificate = _timestampRootCa.CloneIssuerCert();\n            _timestampingIntermediateCertificate = timestampIntermediateCa.CloneIssuerCert();\n\n            _timestampService = TimestampService.Create(timestampIntermediateCa, server);\n\n            TimestampServiceUrl = _timestampService.Url;\n        }\n\n        public void Dispose()\n        {\n            _timestampRootCa.Dispose();\n            _timestampIntermediateCa.Dispose();\n            _timestampingRootCertificate.Dispose();\n            _timestampingIntermediateCertificate.Dispose();\n            _timestampService.Dispose();\n\n            TestUtility.RemoveTestIntermediateCertificates();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CommitmentTypeIndication.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5126 (https://tools.ietf.org/html/rfc5126.html#section-5.11.1):\n\n            CommitmentTypeIndication ::= SEQUENCE {\n              commitmentTypeId CommitmentTypeIdentifier,\n              commitmentTypeQualifier SEQUENCE SIZE (1..MAX) OF\n                             CommitmentTypeQualifier OPTIONAL}\n\n            CommitmentTypeIdentifier ::= OBJECT IDENTIFIER\n\t*/\n    internal sealed class CommitmentTypeIndication\n    {\n        internal Oid CommitmentTypeId { get; }\n        internal IReadOnlyList<CommitmentTypeQualifier>? Qualifiers { get; }\n\n        internal CommitmentTypeIndication(\n            Oid commitmentTypeId,\n            IReadOnlyList<CommitmentTypeQualifier>? qualifiers = null)\n        {\n            ArgumentNullException.ThrowIfNull(commitmentTypeId, nameof(commitmentTypeId));\n\n            CommitmentTypeId = commitmentTypeId;\n            Qualifiers = qualifiers;\n        }\n\n        internal static CommitmentTypeIndication Decode(ReadOnlyMemory<byte> bytes)\n        {\n            AsnReader reader = new(bytes, AsnEncodingRules.DER);\n\n            return Decode(reader);\n        }\n\n        internal static CommitmentTypeIndication Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader indicationReader = reader.ReadSequence();\n            Oid commitmentTypeId = new(indicationReader.ReadObjectIdentifier());\n            List<CommitmentTypeQualifier>? qualifiers = null;\n\n            if (indicationReader.HasData)\n            {\n                AsnReader qualifierReader = indicationReader.ReadSequence();\n\n                qualifiers = new List<CommitmentTypeQualifier>();\n\n                while (qualifierReader.HasData)\n                {\n                    CommitmentTypeQualifier qualifier = CommitmentTypeQualifier.Decode(qualifierReader);\n\n                    qualifiers.Add(qualifier);\n                }\n\n                if (qualifiers.Count == 0)\n                {\n                    throw new AsnContentException();\n                }\n\n                qualifierReader.ThrowIfNotEmpty();\n            }\n\n            indicationReader.ThrowIfNotEmpty();\n\n            return new CommitmentTypeIndication(commitmentTypeId, qualifiers);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(CommitmentTypeId.Value!);\n\n                if (Qualifiers is not null && Qualifiers.Count > 0)\n                {\n                    using (writer.PushSequence())\n                    {\n                        foreach (CommitmentTypeQualifier qualifier in Qualifiers)\n                        {\n                            ReadOnlyMemory<byte> encoded = qualifier.Encode();\n\n                            writer.WriteEncodedValue(encoded.Span);\n                        }\n                    }\n                }\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CommitmentTypeQualifier.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5126 (https://tools.ietf.org/html/rfc5126.html#section-5.11.1):\n\n            CommitmentTypeQualifier ::= SEQUENCE {\n               commitmentTypeIdentifier   CommitmentTypeIdentifier,\n               qualifier                  ANY DEFINED BY commitmentTypeIdentifier }\n\n            CommitmentTypeIdentifier ::= OBJECT IDENTIFIER\n\t*/\n    internal sealed class CommitmentTypeQualifier\n    {\n        internal Oid CommitmentTypeIdentifier { get; }\n        internal ReadOnlyMemory<byte>? Qualifier { get; }\n\n        internal CommitmentTypeQualifier(\n            Oid commitmentTypeIdentifier,\n            ReadOnlyMemory<byte>? qualifier = null)\n        {\n            ArgumentNullException.ThrowIfNull(commitmentTypeIdentifier, nameof(commitmentTypeIdentifier));\n\n            CommitmentTypeIdentifier = commitmentTypeIdentifier;\n            Qualifier = qualifier;\n        }\n\n        internal static CommitmentTypeQualifier Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader commitmentTypeQualifierReader = reader.ReadSequence();\n            Oid commitmentTypeIdentifier = new(commitmentTypeQualifierReader.ReadObjectIdentifier());\n            ReadOnlyMemory<byte>? qualifier = null;\n\n            if (commitmentTypeQualifierReader.HasData)\n            {\n                qualifier = commitmentTypeQualifierReader.ReadEncodedValue();\n            }\n\n            commitmentTypeQualifierReader.ThrowIfNotEmpty();\n\n            return new CommitmentTypeQualifier(commitmentTypeIdentifier, qualifier);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(CommitmentTypeIdentifier.Value!);\n\n                if (Qualifier.HasValue)\n                {\n                    writer.WriteEncodedValue(Qualifier.Value.Span);\n                }\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/CrlResponder.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class CrlResponder : HttpResponder\n    {\n        private readonly CertificateAuthority _certificateAuthority;\n        private readonly TimeSpan? _responseDelay;\n\n        public override Uri Url { get; }\n\n        internal CrlResponder(\n            CertificateAuthority certificateAuthority,\n            TimeSpan? responseDelay = null)\n        {\n            ArgumentNullException.ThrowIfNull(certificateAuthority, nameof(certificateAuthority));\n\n            _certificateAuthority = certificateAuthority;\n            _responseDelay = responseDelay;\n\n            if (certificateAuthority.CdpUri is null)\n            {\n                throw new ArgumentException(message: null, nameof(certificateAuthority));\n            }\n\n            Url = new Uri(certificateAuthority.CdpUri, UriKind.Absolute);\n        }\n\n        public override async Task RespondAsync(HttpContext context)\n        {\n            if (_responseDelay.HasValue)\n            {\n                Trace.WriteLine($\"Delaying response by {_responseDelay.Value}.\");\n\n                await Task.Delay(_responseDelay.Value);\n            }\n\n            byte[] crl = _certificateAuthority.GetCrl();\n\n            context.Response.StatusCode = 200;\n            context.Response.ContentType = \"application/pkix-crl\";\n\n            await context.Response.Body.WriteAsync(crl);\n\n            Trace.WriteLine($\"[CRL]  Responded with {crl.Length}-byte CRL from {_certificateAuthority.SubjectName}.\");\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/EssCertId.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 2634 (https://tools.ietf.org/html/rfc2634#section-5.4.1):\n\n            ESSCertID ::=  SEQUENCE {\n                certHash                 Hash,\n                issuerSerial             IssuerSerial OPTIONAL\n            }\n\n            Hash ::= OCTET STRING -- SHA1 hash of entire certificate\n\n            IssuerSerial ::= SEQUENCE {\n                issuer                   GeneralNames,\n                serialNumber             CertificateSerialNumber\n            }\n\t*/\n    internal sealed class EssCertId\n    {\n        internal ReadOnlyMemory<byte> CertificateHash { get; }\n        internal IssuerSerial? IssuerSerial { get; }\n\n        private EssCertId(ReadOnlyMemory<byte> hash, IssuerSerial? issuerSerial)\n        {\n            CertificateHash = hash;\n            IssuerSerial = issuerSerial;\n        }\n\n        internal static EssCertId Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader sequenceReader = reader.ReadSequence();\n            byte[] hash = sequenceReader.ReadOctetString();\n            IssuerSerial? issuerSerial = null;\n\n            if (sequenceReader.HasData)\n            {\n                issuerSerial = IssuerSerial.Decode(sequenceReader);\n\n                sequenceReader.ThrowIfNotEmpty();\n            }\n\n            return new EssCertId(hash, issuerSerial);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/EssCertIdV2.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5035 (https://tools.ietf.org/html/rfc5035):\n\n            ESSCertIDv2 ::= SEQUENCE {\n                hashAlgorithm            AlgorithmIdentifier\n                       DEFAULT {algorithm id-sha256},\n                certHash                 Hash,\n                issuerSerial             IssuerSerial OPTIONAL\n            }\n\n            Hash ::= OCTET STRING\n\n            IssuerSerial ::= SEQUENCE {\n                issuer                   GeneralNames,\n                serialNumber             CertificateSerialNumber\n           }\n\t*/\n    internal sealed class EssCertIdV2\n    {\n        private static readonly AlgorithmIdentifier DefaultHashAlgorithm = new(Oids.Sha256);\n\n        internal AlgorithmIdentifier HashAlgorithm { get; }\n        internal ReadOnlyMemory<byte> CertificateHash { get; }\n        internal IssuerSerial? IssuerSerial { get; }\n\n        internal EssCertIdV2(\n            AlgorithmIdentifier? hashAlgorithm,\n            ReadOnlyMemory<byte> hash,\n            IssuerSerial? issuerSerial)\n        {\n            HashAlgorithm = hashAlgorithm ?? DefaultHashAlgorithm;\n            CertificateHash = hash;\n            IssuerSerial = issuerSerial;\n        }\n\n        internal static EssCertIdV2 Create(X509Certificate2 certificate, HashAlgorithmName hashAlgorithmName)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            AlgorithmIdentifier algorithm = new(hashAlgorithmName.ToOid());\n            ReadOnlyMemory<byte> hash = certificate.Hash(hashAlgorithmName);\n            IssuerSerial issuerSerial = IssuerSerial.Create(certificate);\n\n            return new EssCertIdV2(algorithm, hash, issuerSerial);\n        }\n\n        internal static EssCertIdV2 Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader sequenceReader = reader.ReadSequence();\n\n            AlgorithmIdentifier algorithm;\n\n            if (sequenceReader.PeekTag() == Asn1Tag.Sequence)\n            {\n                algorithm = AlgorithmIdentifier.Decode(sequenceReader);\n            }\n            else\n            {\n                algorithm = new AlgorithmIdentifier(Oids.Sha256);\n            }\n\n            byte[] hash = sequenceReader.ReadOctetString();\n            IssuerSerial? issuerSerial = null;\n\n            if (sequenceReader.HasData)\n            {\n                issuerSerial = IssuerSerial.Decode(sequenceReader);\n            }\n\n            sequenceReader.ThrowIfNotEmpty();\n\n            return new EssCertIdV2(algorithm, hash, issuerSerial);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                if (HashAlgorithm is not null && !HashAlgorithm.Algorithm.IsEqualTo(Oids.Sha256))\n                {\n                    writer.WriteEncodedValue(HashAlgorithm.Encode().Span);\n                }\n\n                writer.WriteOctetString(CertificateHash.Span);\n\n                if (IssuerSerial is not null)\n                {\n                    writer.WriteEncodedValue(IssuerSerial.Encode().Span);\n                }\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/GeneralName.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 3280 (https://tools.ietf.org/html/rfc3280#section-4.2.1.7):\n\n            GeneralName ::= CHOICE {\n                    otherName                       [0]     OtherName,\n                    rfc822Name                      [1]     IA5String,\n                    dNSName                         [2]     IA5String,\n                    x400Address                     [3]     ORAddress,\n                    directoryName                   [4]     Name,\n                    ediPartyName                    [5]     EDIPartyName,\n                    uniformResourceIdentifier       [6]     IA5String,\n                    iPAddress                       [7]     OCTET STRING,\n                    registeredID                    [8]     OBJECT IDENTIFIER }\n\n                OtherName ::= SEQUENCE {\n                    type-id    OBJECT IDENTIFIER,\n                    value      [0] EXPLICIT ANY DEFINED BY type-id }\n\n                EDIPartyName ::= SEQUENCE {\n                    nameAssigner            [0]     DirectoryString OPTIONAL,\n                    partyName               [1]     DirectoryString }\n\n\n        From RFC 2459 (https://tools.ietf.org/html/rfc2459.html#section-4.1.2.4):\n\n            Name ::= CHOICE {\n                RDNSequence }\n\n            RDNSequence ::= SEQUENCE OF RelativeDistinguishedName\n\n            RelativeDistinguishedName ::=\n                SET OF AttributeTypeAndValue\n\n            AttributeTypeAndValue ::= SEQUENCE {\n                type     AttributeType,\n                value    AttributeValue }\n\n            AttributeType ::= OBJECT IDENTIFIER\n\n            AttributeValue ::= ANY DEFINED BY AttributeType\n\t*/\n    internal sealed class GeneralName\n    {\n        // Per RFC 2634 section 5.4.1 (https://tools.ietf.org/html/rfc2634#section-5.4.1)\n        // only the directory name choice (#4) is allowed.\n        private static readonly Asn1Tag Tag = new(TagClass.ContextSpecific, tagValue: 4, isConstructed: true);\n\n        internal X500DistinguishedName DirectoryName { get; }\n\n        internal GeneralName(X500DistinguishedName directoryName)\n        {\n            ArgumentNullException.ThrowIfNull(directoryName, nameof(directoryName));\n\n            DirectoryName = directoryName;\n        }\n\n        internal static GeneralName Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            Asn1Tag nextTag = reader.PeekTag();\n\n            if (nextTag.Equals(Tag))\n            {\n                AsnReader nameReader = reader.ReadSequence(Tag);\n                ReadOnlyMemory<byte> bytes = nameReader.ReadEncodedValue();\n\n                nameReader.ThrowIfNotEmpty();\n\n                X500DistinguishedName directoryName = new(bytes.Span);\n\n                return new GeneralName(directoryName);\n            }\n\n            throw new AsnContentException();\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence(Tag))\n            {\n                writer.WriteEncodedValue(DirectoryName.RawData);\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/HashAlgorithmNameExtensions.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    internal static class HashAlgorithmNameExtensions\n    {\n        internal static Oid ToOid(this HashAlgorithmName hashAlgorithmName)\n        {\n            if (hashAlgorithmName == HashAlgorithmName.SHA256)\n            {\n                return Oids.Sha256;\n            }\n\n            if (hashAlgorithmName == HashAlgorithmName.SHA384)\n            {\n                return Oids.Sha384;\n            }\n\n            if (hashAlgorithmName == HashAlgorithmName.SHA512)\n            {\n                return Oids.Sha512;\n            }\n\n            throw new ArgumentException(null, nameof(hashAlgorithmName));\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/HttpResponder.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing Microsoft.AspNetCore.Http;\n\nnamespace Sign.Core.Test\n{\n    internal abstract class HttpResponder : IHttpResponder\n    {\n        public abstract Uri Url { get; }\n\n        public abstract Task RespondAsync(HttpContext context);\n\n        protected static bool IsGet(HttpRequest request)\n        {\n            return string.Equals(request.Method, \"GET\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        protected static bool IsPost(HttpRequest request)\n        {\n            return string.Equals(request.Method, \"POST\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        protected static byte[] ReadRequestBody(HttpRequest request)\n        {\n            if (request.ContentLength is null)\n            {\n                return Array.Empty<byte>();\n            }\n\n            using (BinaryReader reader = new(request.Body))\n            {\n                return reader.ReadBytes((int)request.ContentLength);\n            }\n        }\n\n        protected static void WriteResponseBody(HttpResponse response, ReadOnlyMemory<byte> bytes)\n        {\n            response.ContentLength = bytes.Length;\n\n            using (BinaryWriter writer = new(response.Body))\n            {\n                writer.Write(bytes.Span);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/IHttpResponder.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing Microsoft.AspNetCore.Http;\n\nnamespace Sign.Core.Test\n{\n    internal interface IHttpResponder\n    {\n        Uri Url { get; }\n\n        Task RespondAsync(HttpContext context);\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/ITestServer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal interface ITestServer : IDisposable\n    {\n        Uri Url { get; }\n\n        IDisposable RegisterResponder(IHttpResponder responder);\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/IssuerSerial.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 2634 (https://tools.ietf.org/html/rfc2634#section-5.4.1):\n\n            IssuerSerial ::= SEQUENCE {\n                issuer                   GeneralNames,\n                serialNumber             CertificateSerialNumber\n            }\n\n        From RFC 2634 (https://tools.ietf.org/html/rfc3280#section-4.2.1.7):\n\n            GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName\n\n        From RFC 3280 (https://tools.ietf.org/html/rfc3280#section-4.1):\n\n            CertificateSerialNumber  ::=  INTEGER\n\t*/\n    internal sealed class IssuerSerial\n    {\n        internal IReadOnlyList<GeneralName> GeneralNames { get; }\n        internal ReadOnlyMemory<byte> SerialNumber { get; } // big endian\n\n        internal IssuerSerial(IReadOnlyList<GeneralName> generalNames, ReadOnlyMemory<byte> serialNumber)\n        {\n            ArgumentNullException.ThrowIfNull(generalNames, nameof(generalNames));\n\n            GeneralNames = generalNames;\n            SerialNumber = serialNumber;\n        }\n\n        internal static IssuerSerial Create(X509Certificate2 certificate)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            GeneralName[] generalNames = new[] { new GeneralName(certificate.IssuerName) };\n            byte[] serialNumber = certificate.GetSerialNumber();\n\n            // Convert from little endian to big endian.\n            Array.Reverse(serialNumber);\n\n            return new IssuerSerial(generalNames, serialNumber);\n        }\n\n        internal static IssuerSerial Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader sequenceReader = reader.ReadSequence();\n            IReadOnlyList<GeneralName> generalNames = ReadGeneralNames(sequenceReader);\n            ReadOnlyMemory<byte> serialNumber = sequenceReader.ReadIntegerBytes();\n\n            sequenceReader.ThrowIfNotEmpty();\n\n            return new IssuerSerial(generalNames, serialNumber);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            // Per RFC 5280 section 4.1.2.2 (https://tools.ietf.org/html/rfc5280#section-4.1.2.2)\n            // serial number must be an unsigned integer.\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                using (writer.PushSequence())\n                {\n                    foreach (GeneralName generalName in GeneralNames)\n                    {\n                        ReadOnlyMemory<byte> encoded = generalName.Encode();\n\n                        writer.WriteEncodedValue(encoded.Span);\n                    }\n                }\n\n                writer.WriteIntegerUnsigned(SerialNumber.Span);\n            }\n\n            return writer.Encode();\n        }\n\n        private static IReadOnlyList<GeneralName> ReadGeneralNames(AsnReader reader)\n        {\n            AsnReader sequenceReader = reader.ReadSequence();\n            List<GeneralName> generalNames = new(capacity: 1);\n\n            GeneralName? generalName = GeneralName.Decode(sequenceReader);\n\n            if (generalName is not null)\n            {\n                generalNames.Add(generalName);\n            }\n\n            sequenceReader.ThrowIfNotEmpty();\n\n            return generalNames;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/OcspResponder.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Diagnostics;\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\nusing System.Web;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class OcspResponder : HttpResponder\n    {\n        private readonly CertificateAuthority _certificateAuthority;\n        private readonly TimeSpan? _responseDelay;\n\n        public override Uri Url { get; }\n\n        internal OcspResponder(\n            CertificateAuthority certificateAuthority,\n            TimeSpan? responseDelay = null)\n        {\n            ArgumentNullException.ThrowIfNull(certificateAuthority, nameof(certificateAuthority));\n\n            _certificateAuthority = certificateAuthority;\n            _responseDelay = responseDelay;\n\n            if (certificateAuthority.OcspUri is null)\n            {\n                throw new ArgumentException(message: null, nameof(certificateAuthority));\n            }\n\n            Url = new Uri(certificateAuthority.OcspUri, UriKind.Absolute);\n        }\n\n        public override async Task RespondAsync(HttpContext context)\n        {\n            if (_responseDelay.HasValue)\n            {\n                Trace.WriteLine($\"Delaying response by {_responseDelay.Value}.\");\n\n                await Task.Delay(_responseDelay.Value);\n            }\n\n            byte[] requestBytes;\n\n            try\n            {\n                if (context.Request.Method == \"GET\")\n                {\n                    string base64 = HttpUtility.UrlDecode(context.Request.Path.Value[(context.Request.PathBase.Value.Length + 1)..]);\n                    requestBytes = Convert.FromBase64String(base64);\n                }\n                else if (context.Request.Method == \"POST\" && context.Request.ContentType == \"application/ocsp-request\")\n                {\n                    using (Stream stream = context.Request.Body)\n                    {\n                        requestBytes = new byte[context.Request.ContentLength!.Value];\n                        int read = stream.Read(requestBytes, 0, requestBytes.Length);\n                        Debug.Assert(read == requestBytes.Length);\n                    }\n                }\n                else\n                {\n                    return;\n                }\n            }\n            catch (Exception e)\n            {\n                Trace.WriteLine($\"Failed to get OCSP request bytes ({context.Request.Path}) - {e}\");\n\n                return;\n            }\n\n            ReadOnlyMemory<byte> certId;\n            ReadOnlyMemory<byte> nonce;\n            try\n            {\n                DecodeOcspRequest(requestBytes, out certId, out nonce);\n            }\n            catch (Exception e)\n            {\n                Trace.WriteLine($\"OcspRequest Decode failed ({context.Request.Path}) - {e}\");\n                context.Response.StatusCode = 400;\n                return;\n            }\n\n            byte[] ocspResponse = _certificateAuthority.BuildOcspResponse(certId, nonce);\n\n            if (_responseDelay.HasValue)\n            {\n                Trace.WriteLine($\"Delaying response by {_responseDelay.Value}.\");\n\n                await Task.Delay(_responseDelay.Value);\n            }\n\n            context.Response.StatusCode = 200;\n            context.Response.ContentType = \"application/ocsp-response\";\n            await context.Response.Body.WriteAsync(ocspResponse);\n\n            if (_certificateAuthority.HasOcspDelegation)\n            {\n                Trace.WriteLine($\"[OCSP]  Responded with {ocspResponse.Length}-byte certificate status from {_certificateAuthority.SubjectName} delegated to {_certificateAuthority.OcspResponderSubjectName}\");\n            }\n            else\n            {\n                Trace.WriteLine($\"[OCSP]  Responded with {ocspResponse.Length}-byte certificate status from {_certificateAuthority.SubjectName}\");\n            }\n        }\n\n        private static void DecodeOcspRequest(\n            byte[] requestBytes,\n            out ReadOnlyMemory<byte> certId,\n            out ReadOnlyMemory<byte> nonceExtension)\n        {\n            Asn1Tag context0 = new(TagClass.ContextSpecific, 0);\n            Asn1Tag context1 = new(TagClass.ContextSpecific, 1);\n\n            AsnReader reader = new(requestBytes, AsnEncodingRules.DER);\n            AsnReader request = reader.ReadSequence();\n            reader.ThrowIfNotEmpty();\n\n            AsnReader tbsRequest = request.ReadSequence();\n\n            if (request.HasData)\n            {\n                // Optional signature\n                request.ReadEncodedValue();\n                request.ThrowIfNotEmpty();\n            }\n\n            // Only v1(0) is supported, and it shouldn't be written per DER.\n            // But Apple writes it anyways, so let's go ahead and be lenient.\n            if (tbsRequest.PeekTag().HasSameClassAndValue(context0))\n            {\n                AsnReader versionReader = tbsRequest.ReadSequence(context0);\n\n                if (!versionReader.TryReadInt32(out int version) || version != 0)\n                {\n                    throw new CryptographicException(\"ASN1 corrupted data\");\n                }\n\n                versionReader.ThrowIfNotEmpty();\n            }\n\n            if (tbsRequest.PeekTag().HasSameClassAndValue(context1))\n            {\n                tbsRequest.ReadEncodedValue();\n            }\n\n            AsnReader requestList = tbsRequest.ReadSequence();\n            AsnReader? requestExtensions = null;\n\n            if (tbsRequest.HasData)\n            {\n                AsnReader requestExtensionsWrapper = tbsRequest.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));\n                requestExtensions = requestExtensionsWrapper.ReadSequence();\n                requestExtensionsWrapper.ThrowIfNotEmpty();\n            }\n\n            tbsRequest.ThrowIfNotEmpty();\n\n            AsnReader firstRequest = requestList.ReadSequence();\n            requestList.ThrowIfNotEmpty();\n\n            certId = firstRequest.ReadEncodedValue();\n\n            if (firstRequest.HasData)\n            {\n                firstRequest.ReadSequence(context0);\n            }\n\n            firstRequest.ThrowIfNotEmpty();\n\n            nonceExtension = default;\n\n            if (requestExtensions != null)\n            {\n                while (requestExtensions.HasData)\n                {\n                    ReadOnlyMemory<byte> wholeExtension = requestExtensions.PeekEncodedValue();\n                    AsnReader extension = requestExtensions.ReadSequence();\n\n                    if (extension.ReadObjectIdentifier() == \"1.3.6.1.5.5.7.48.1.2\")\n                    {\n                        nonceExtension = wholeExtension;\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/OidExtensions.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    internal static class OidExtensions\n    {\n        internal static bool IsEqualTo(this Oid oid, Oid other)\n        {\n            ArgumentNullException.ThrowIfNull(oid, nameof(oid));\n            ArgumentNullException.ThrowIfNull(other, nameof(other));\n\n            return string.Equals(oid.Value, other.Value, StringComparison.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/Oids.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    internal static class Oids\n    {\n        internal static readonly Oid AnyPolicy = new(DottedDecimalValues.AnyPolicy);\n        internal static readonly Oid CodeSigningEku = new(DottedDecimalValues.CodeSigningEku);\n        internal static readonly Oid IdQtCps = new(DottedDecimalValues.IdQtCps);\n        internal static readonly Oid IdQtUnotice = new(DottedDecimalValues.IdQtUnotice);\n        internal static readonly Oid MicrosoftRfc3161Timestamp = new(DottedDecimalValues.MicrosoftRfc3161Timestamp);\n        internal static readonly Oid Sha1 = new(DottedDecimalValues.Sha1);\n        internal static readonly Oid Sha256 = new(DottedDecimalValues.Sha256);\n        internal static readonly Oid Sha384 = new(DottedDecimalValues.Sha384);\n        internal static readonly Oid Sha512 = new(DottedDecimalValues.Sha512);\n        internal static readonly Oid SigningCertificateV2 = new(DottedDecimalValues.SigningCertificateV2);\n        internal static readonly Oid Test = new(DottedDecimalValues.Test);\n        internal static readonly Oid TestCertPolicyOne = new(DottedDecimalValues.TestCertPolicyOne);\n        internal static readonly Oid TimeStampingEku = new(DottedDecimalValues.TimeStampingEku);\n        internal static readonly Oid TSTInfoContentType = new(DottedDecimalValues.TSTInfoContentType);\n\n        private static class DottedDecimalValues\n        {\n            // RFC 5280 \"anyPolicy\" (https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4)\n            internal const string AnyPolicy = \"2.5.29.32.0\";\n\n            // RFC 5280 codeSigning attribute, (https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12)\n            internal const string CodeSigningEku = \"1.3.6.1.5.5.7.3.3\";\n\n            // RFC 5280 \"id-qt-cps\" (https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4)\n            internal const string IdQtCps = \"1.3.6.1.5.5.7.2.1\";\n\n            // RFC 5280 \"id-qt-unotice\" (https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4)\n            internal const string IdQtUnotice = \"1.3.6.1.5.5.7.2.2\";\n\n            // \"szOID_RFC3161_counterSign\" from wincrypt.h\n            internal const string MicrosoftRfc3161Timestamp = \"1.3.6.1.4.1.311.3.3.1\";\n\n            // RFC 8017 appendix B.1 (https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.1)\n            internal const string Sha1 = \"1.3.14.3.2.26\";\n\n            // RFC 8017 appendix B.1 (https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.1)\n            internal const string Sha256 = \"2.16.840.1.101.3.4.2.1\";\n\n            // RFC 8017 appendix B.1 (https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.1)\n            internal const string Sha384 = \"2.16.840.1.101.3.4.2.2\";\n\n            // RFC 8017 appendix B.1 (https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.1)\n            internal const string Sha512 = \"2.16.840.1.101.3.4.2.3\";\n\n            // RFC 5126 \"signing-certificate-v2\" (https://datatracker.ietf.org/doc/html/rfc5126.html#page-34)\n            internal const string SigningCertificateV2 = \"1.2.840.113549.1.9.16.2.47\";\n\n            // RFC 7229 \"id-TEST\" https://datatracker.ietf.org/doc/html/rfc7229#section-2\n            internal const string Test = \"1.3.6.1.5.5.7.13\";\n\n            // RFC 7229 \"id-TEST-certPolicyOne\" https://datatracker.ietf.org/doc/html/rfc7229#section-2\n            internal const string TestCertPolicyOne = \"1.3.6.1.5.5.7.13.1\";\n\n            // RFC 3280 \"id-kp-timeStamping\" (https://datatracker.ietf.org/doc/html/rfc3280.html#section-4.2.1.13)\n            internal const string TimeStampingEku = \"1.3.6.1.5.5.7.3.8\";\n\n            // RFC 3161 \"id-ct-TSTInfo\" https://datatracker.ietf.org/doc/html/rfc3161#section-2.4.2\n            internal const string TSTInfoContentType = \"1.2.840.113549.1.9.16.1.4\";\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/PfxFilesFixture.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    public sealed class PfxFilesFixture : IDisposable\n    {\n        private readonly DirectoryService _directoryService;\n        private readonly TemporaryDirectory _directory;\n        private readonly ConcurrentDictionary<Tuple<int, HashAlgorithmName>, FileInfo> _pfxFiles;\n\n        public PfxFilesFixture()\n        {\n            _directoryService = new DirectoryService(Mock.Of<ILogger<IDirectoryService>>());\n            _directory = new TemporaryDirectory(_directoryService);\n            _pfxFiles = new ConcurrentDictionary<Tuple<int, HashAlgorithmName>, FileInfo>();\n        }\n\n        internal X509Certificate2 GetPfx(int keySizeInBits, HashAlgorithmName hashAlgorithmName)\n        {\n            FileInfo file = _pfxFiles.GetOrAdd(\n                new Tuple<int, HashAlgorithmName>(keySizeInBits, hashAlgorithmName),\n                tuple => CreateSelfIssuedCertificate(tuple.Item1, tuple.Item2));\n\n            return new X509Certificate2(file.FullName);\n        }\n\n        public void Dispose()\n        {\n            _directory.Dispose();\n            _directoryService.Dispose();\n        }\n\n        private FileInfo CreateSelfIssuedCertificate(int keySizeInBits, HashAlgorithmName hashAlgorithmName)\n        {\n            using (RSA rsa = RSA.Create(keySizeInBits))\n            {\n                CertificateRequest certificateRequest = new(\n                    subjectName: \"CN=Sign CLI, OU=TEST, O=TEST\",\n                    rsa,\n                    hashAlgorithmName,\n                    // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                    RSASignaturePadding.Pkcs1);\n\n                certificateRequest.CertificateExtensions.Add(\n                    new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true));\n                certificateRequest.CertificateExtensions.Add(\n                    new X509EnhancedKeyUsageExtension(new OidCollection() { Oids.CodeSigningEku }, critical: false));\n\n                DateTimeOffset now = DateTimeOffset.Now;\n                DateTimeOffset notBefore = now.AddMinutes(-1);\n                DateTimeOffset notAfter = now.AddMinutes(15);\n\n                using (X509Certificate2 certificate = certificateRequest.CreateSelfSigned(notBefore, notAfter))\n                {\n                    FileInfo file = new(Path.Combine(_directory.Directory.FullName, $\"{certificate.Thumbprint}.pfx\"));\n                    byte[] bytes = certificate.Export(X509ContentType.Pfx);\n\n                    File.WriteAllBytes(file.FullName, bytes);\n\n                    return file;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/PolicyInformation.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5280 (https://tools.ietf.org/html/rfc5280#appendix-A.2):\n\n            PolicyInformation ::= SEQUENCE {\n                policyIdentifier   CertPolicyId,\n                policyQualifiers   SEQUENCE SIZE (1..MAX) OF\n                                        PolicyQualifierInfo OPTIONAL }\n\n            CertPolicyId ::= OBJECT IDENTIFIER\n\t*/\n    internal sealed class PolicyInformation\n    {\n        internal Oid PolicyIdentifier { get; }\n        internal IReadOnlyList<PolicyQualifierInfo>? PolicyQualifiers { get; }\n\n        internal PolicyInformation(Oid policyIdentifier, IReadOnlyList<PolicyQualifierInfo>? policyQualifiers)\n        {\n            ArgumentNullException.ThrowIfNull(policyIdentifier, nameof(policyIdentifier));\n\n            PolicyIdentifier = policyIdentifier;\n            PolicyQualifiers = policyQualifiers;\n        }\n\n        internal static PolicyInformation Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader policyInfoReader = reader.ReadSequence();\n            Oid policyIdentifier = new(policyInfoReader.ReadObjectIdentifier());\n            bool isAnyPolicy = policyIdentifier.IsEqualTo(Oids.AnyPolicy);\n            IReadOnlyList<PolicyQualifierInfo>? policyQualifiers = null;\n\n            if (policyInfoReader.HasData)\n            {\n                policyQualifiers = ReadPolicyQualifiers(policyInfoReader, isAnyPolicy);\n            }\n\n            policyInfoReader.ThrowIfNotEmpty();\n\n            return new PolicyInformation(policyIdentifier, policyQualifiers);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(PolicyIdentifier.Value!);\n\n                if (PolicyQualifiers is not null)\n                {\n                    using (writer.PushSequence())\n                    {\n                        foreach (PolicyQualifierInfo policyQualifier in PolicyQualifiers)\n                        {\n                            ReadOnlyMemory<byte> bytes = policyQualifier.Encode();\n\n                            writer.WriteEncodedValue(bytes.Span);\n                        }\n                    }\n                }\n            }\n\n            return writer.Encode();\n        }\n\n        private static IReadOnlyList<PolicyQualifierInfo> ReadPolicyQualifiers(AsnReader reader, bool isAnyPolicy)\n        {\n            AsnReader policyQualifiersReader = reader.ReadSequence();\n            List<PolicyQualifierInfo> policyQualifiers = new();\n\n            while (policyQualifiersReader.HasData)\n            {\n                PolicyQualifierInfo policyQualifier = PolicyQualifierInfo.Decode(policyQualifiersReader);\n\n                if (isAnyPolicy)\n                {\n                    if (!policyQualifier.PolicyQualifierId.IsEqualTo(Oids.IdQtCps) &&\n                        !policyQualifier.PolicyQualifierId.IsEqualTo(Oids.IdQtUnotice))\n                    {\n                        throw new AsnContentException();\n                    }\n                }\n\n                policyQualifiers.Add(policyQualifier);\n            }\n\n            if (policyQualifiers.Count == 0)\n            {\n                throw new AsnContentException();\n            }\n\n            return policyQualifiers.AsReadOnly();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/PolicyQualifierInfo.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5280 (https://tools.ietf.org/html/rfc5280#appendix-A.2):\n\n            PolicyQualifierInfo ::= SEQUENCE {\n                policyQualifierId  PolicyQualifierId,\n                qualifier          ANY DEFINED BY policyQualifierId }\n\n            -- policyQualifierIds for Internet policy qualifiers\n\n            id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }\n            id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }\n            id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }\n\n            PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )\n\t*/\n    internal sealed class PolicyQualifierInfo\n    {\n        internal Oid PolicyQualifierId { get; }\n        internal ReadOnlyMemory<byte>? Qualifier { get; }\n\n        internal PolicyQualifierInfo(Oid policyQualifierId, ReadOnlyMemory<byte>? qualifier)\n        {\n            ArgumentNullException.ThrowIfNull(policyQualifierId, nameof(policyQualifierId));\n\n            PolicyQualifierId = policyQualifierId;\n            Qualifier = qualifier;\n        }\n\n        internal static PolicyQualifierInfo Decode(AsnReader reader)\n        {\n            ArgumentNullException.ThrowIfNull(reader, nameof(reader));\n\n            AsnReader policyQualifierReader = reader.ReadSequence();\n            Oid policyQualifierId = new(policyQualifierReader.ReadObjectIdentifier());\n            ReadOnlyMemory<byte>? qualifier = null;\n\n            if (policyQualifierReader.HasData)\n            {\n                qualifier = policyQualifierReader.ReadEncodedValue();\n            }\n\n            policyQualifierReader.ThrowIfNotEmpty();\n\n            return new PolicyQualifierInfo(policyQualifierId, qualifier);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteObjectIdentifier(PolicyQualifierId.Value!);\n\n                if (Qualifier.HasValue)\n                {\n                    writer.WriteEncodedValue(Qualifier.Value.Span);\n                }\n            }\n\n            return writer.Encode();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/SigningCertificateV2.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    /*\n        From RFC 5035 (https://tools.ietf.org/html/rfc5035):\n\n            SigningCertificateV2 ::= SEQUENCE {\n                certs        SEQUENCE OF ESSCertIDv2,\n                policies     SEQUENCE OF PolicyInformation OPTIONAL\n            }\n\t*/\n    internal sealed class SigningCertificateV2\n    {\n        internal IReadOnlyList<EssCertIdV2> Certificates { get; }\n        internal IReadOnlyList<PolicyInformation>? Policies { get; }\n\n        private SigningCertificateV2(\n            IReadOnlyList<EssCertIdV2> certificates,\n            IReadOnlyList<PolicyInformation>? policies)\n        {\n            Certificates = certificates;\n            Policies = policies;\n        }\n\n        internal static SigningCertificateV2 Create(X509Certificate2 certificate, HashAlgorithmName hashAlgorithmName)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            EssCertIdV2 essCertIdV2 = EssCertIdV2.Create(certificate, hashAlgorithmName);\n\n            return new SigningCertificateV2(new[] { essCertIdV2 }, policies: null);\n        }\n\n        internal static SigningCertificateV2 Decode(ReadOnlyMemory<byte> bytes)\n        {\n            AsnReader reader = new(bytes, AsnEncodingRules.DER);\n\n            return Decode(reader);\n        }\n\n        internal static SigningCertificateV2 Decode(AsnReader reader)\n        {\n            AsnReader sequenceReader = reader.ReadSequence();\n\n            IReadOnlyList<EssCertIdV2> certificates = ReadCertificates(sequenceReader);\n            IReadOnlyList<PolicyInformation>? policies = null;\n\n            if (sequenceReader.HasData)\n            {\n                policies = ReadPolicies(sequenceReader);\n            }\n\n            sequenceReader.ThrowIfNotEmpty();\n\n            return new SigningCertificateV2(certificates, policies);\n        }\n\n        internal ReadOnlyMemory<byte> Encode()\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                using (writer.PushSequence())\n                {\n                    foreach (EssCertIdV2 certificate in Certificates)\n                    {\n                        writer.WriteEncodedValue(certificate.Encode().Span);\n                    }\n                }\n\n                if (Policies is not null && Policies.Count > 0)\n                {\n                    using (writer.PushSequence())\n                    {\n                        foreach (PolicyInformation policy in Policies)\n                        {\n                            writer.WriteEncodedValue(policy.Encode().Span);\n                        }\n                    }\n                }\n            }\n\n            return writer.Encode();\n        }\n\n        private static IReadOnlyList<EssCertIdV2> ReadCertificates(AsnReader reader)\n        {\n            AsnReader essCertIdV2Reader = reader.ReadSequence();\n            List<EssCertIdV2> certificates = new();\n\n            while (essCertIdV2Reader.HasData)\n            {\n                EssCertIdV2 certificate = EssCertIdV2.Decode(essCertIdV2Reader);\n\n                certificates.Add(certificate);\n            }\n\n            essCertIdV2Reader.ThrowIfNotEmpty();\n\n            return certificates;\n        }\n\n        private static IReadOnlyList<PolicyInformation> ReadPolicies(AsnReader reader)\n        {\n            AsnReader policiesReader = reader.ReadSequence();\n            List<PolicyInformation> policies = new();\n\n            while (policiesReader.HasData)\n            {\n                PolicyInformation policy = PolicyInformation.Decode(policiesReader);\n\n                policies.Add(policy);\n            }\n\n            policiesReader.ThrowIfNotEmpty();\n\n            return policies;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/SigningTestsCollection.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Sign.TestInfrastructure;\n\nnamespace Sign.Core.Test\n{\n    [CollectionDefinition(Name, DisableParallelization = true)]\n    public sealed class SigningTestsCollection :\n        ICollectionFixture<CertificatesFixture>,\n        ICollectionFixture<TrustedCertificateFixture>,\n        ICollectionFixture<TestServerFixture>,\n        ICollectionFixture<PfxFilesFixture>\n    {\n        internal const string Name = nameof(SigningTestsCollection);\n\n        // This class has no code, and is never created. Its purpose is simply\n        // to be the place to apply [CollectionDefinition] and all the\n        // ICollectionFixture<> interfaces.\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/TestServer.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Hosting.Server.Features;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class TestServer : ITestServer, IStartup, IDisposable\n    {\n        private readonly ConcurrentDictionary<string, IHttpResponder> _responders;\n        private IWebHost? _webHost;\n        private Lazy<Uri>? _url;\n\n        public Uri Url => _url!.Value;\n\n        private bool _isDisposed;\n\n        private TestServer()\n        {\n            _responders = new ConcurrentDictionary<string, IHttpResponder>();\n        }\n\n        public void Dispose()\n        {\n            if (!_isDisposed)\n            {\n                _webHost?.Dispose();\n\n                GC.SuppressFinalize(this);\n\n                _isDisposed = true;\n            }\n        }\n\n        public void Configure(IApplicationBuilder app)\n        {\n            ArgumentNullException.ThrowIfNull(app, nameof(app));\n\n            // The actual port isn't known until later so defer retrieval until it is.\n            _url = new Lazy<Uri>(() =>\n            {\n                IServerAddressesFeature? serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>();\n\n                if (serverAddressesFeature is null)\n                {\n                    throw new InvalidOperationException();\n                }\n\n                return new Uri(serverAddressesFeature.Addresses.Single());\n            });\n\n            app.MapWhen(\n                context =>\n                {\n                    if (context.Request.Path.HasValue)\n                    {\n                        return _responders.ContainsKey(context.Request.Path.Value);\n                    }\n\n                    return false;\n                },\n                configuration => configuration.Run(async context =>\n                {\n                    try\n                    {\n                        await _responders[context.Request.Path.Value].RespondAsync(context);\n\n                        Trace.WriteLine($\"Replied:   {context.Request.Path.Value}\");\n                    }\n                    catch (Exception ex)\n                    {\n                        Trace.WriteLine(ex);\n                    }\n                }));\n        }\n\n        public IServiceProvider ConfigureServices(IServiceCollection services)\n        {\n            ArgumentNullException.ThrowIfNull(services, nameof(services));\n\n            return services.BuildServiceProvider();\n        }\n\n        public IDisposable RegisterResponder(IHttpResponder responder)\n        {\n            ArgumentNullException.ThrowIfNull(responder, nameof(responder));\n\n            return new Responder(_responders, responder.Url, responder);\n        }\n\n        internal static async Task<ITestServer> CreateAsync()\n        {\n            TestServer server = new();\n            IWebHostBuilder builder = new WebHostBuilder()\n                .ConfigureServices(services =>\n                {\n                    services.AddSingleton<IStartup>(server);\n                })\n                .UseKestrel()\n                .UseUrls(\"http://127.0.0.1:0\"); // automatically pick the port\n            IWebHost host = builder.Build();\n\n            server._webHost = host;\n\n            await host.StartAsync(CancellationToken.None);\n\n            Trace.WriteLine($\"Test server listening at {server.Url.AbsoluteUri}\");\n\n            return server;\n        }\n\n        private sealed class Responder : IDisposable\n        {\n            private readonly ConcurrentDictionary<string, IHttpResponder> _responders;\n            private readonly string _key;\n\n            internal Responder(ConcurrentDictionary<string, IHttpResponder> responders, Uri url, IHttpResponder responder)\n            {\n                _responders = responders;\n                _key = url.PathAndQuery;\n                _responders[url.PathAndQuery] = responder;\n            }\n\n            public void Dispose()\n            {\n                _responders.TryRemove(_key, out IHttpResponder? _);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/TestServerFixture.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public sealed class TestServerFixture : IDisposable\n    {\n        internal static ITestServer Instance { get; }\n\n        internal ITestServer Server { get; } = Instance;\n\n        static TestServerFixture()\n        {\n            Instance = TestServer.CreateAsync().GetAwaiter().GetResult();\n        }\n\n        public void Dispose()\n        {\n            Server.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/TestUtility.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    internal static class TestUtility\n    {\n        internal static void RemoveTestIntermediateCertificates()\n        {\n            // See https://github.com/dotnet/runtime/blob/07d8b82d54b6b8db16f5fbb531efcb1e276dc264/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs#L99-L122\n            using (X509Store store = new(StoreName.CertificateAuthority, StoreLocation.CurrentUser))\n            {\n                store.Open(OpenFlags.ReadWrite);\n\n                foreach (X509Certificate2 storeCert in store.Certificates)\n                {\n                    if (storeCert.Extensions[Oids.Test.Value!] is not null)\n                    {\n                        store.Remove(storeCert);\n                    }\n\n                    storeCert.Dispose();\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/Server/TimestampService.cs",
    "content": "#pragma warning disable IDE0073\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Formats.Asn1;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.Pkcs;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    // https://tools.ietf.org/html/rfc3161\n    internal sealed class TimestampService : HttpResponder, IDisposable\n    {\n        private const string RequestContentType = \"application/timestamp-query\";\n        private const string ResponseContentType = \"application/timestamp-response\";\n\n        private BigInteger _nextSerialNumber;\n        private IDisposable? _disposable;\n        private readonly DirectoryService _directoryService;\n        private readonly TemporaryDirectory _temporaryDirectory;\n\n        /// <summary>\n        /// Gets this certificate authority's certificate.\n        /// </summary>\n        internal X509Certificate2 Certificate { get; }\n\n        /// <summary>\n        /// Gets the base URI specific to this HTTP responder.\n        /// </summary>\n        public override Uri Url { get; }\n\n        /// <summary>\n        /// Gets the issuing certificate authority.\n        /// </summary>\n        internal CertificateAuthority CertificateAuthority { get; }\n\n        private TimestampService(\n            CertificateAuthority certificateAuthority,\n            X509Certificate2 certificate,\n            Uri uri)\n        {\n            CertificateAuthority = certificateAuthority;\n            Certificate = certificate;\n            Url = uri;\n            _nextSerialNumber = BigInteger.One;\n            _directoryService = new DirectoryService(Mock.Of<ILogger<IDirectoryService>>());\n            _temporaryDirectory = new TemporaryDirectory(_directoryService);\n        }\n\n        public void Dispose()\n        {\n            _disposable?.Dispose();\n            _temporaryDirectory.Dispose();\n            _directoryService.Dispose();\n        }\n\n        internal static TimestampService Create(\n            CertificateAuthority certificateAuthority,\n            ITestServer server,\n            DateTimeOffset? notAfter = null)\n        {\n            ArgumentNullException.ThrowIfNull(certificateAuthority, nameof(certificateAuthority));\n            ArgumentNullException.ThrowIfNull(server, nameof(server));\n\n            using (RSA rsa = RSA.Create(keySizeInBits: 3072))\n            {\n                // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                CertificateRequest request = new(\"CN=timestamp.test\", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n\n                request.CertificateExtensions.Add(\n                    new X509BasicConstraintsExtension(\n                        certificateAuthority: false,\n                        hasPathLengthConstraint: false,\n                        pathLengthConstraint: 0,\n                        critical: true));\n\n                request.CertificateExtensions.Add(\n                    new X509KeyUsageExtension(\n                        X509KeyUsageFlags.DigitalSignature,\n                        critical: true));\n\n                request.CertificateExtensions.Add(\n                    new X509EnhancedKeyUsageExtension(\n                        new OidCollection()\n                        {\n                            Oids.TimeStampingEku\n                        },\n                        critical: true));\n\n                X509Certificate2 certificateWithPrivateKey;\n\n                using (X509Certificate2 certificate = certificateAuthority.Create(request, notAfter))\n                {\n                    certificateWithPrivateKey = certificate.CopyWithPrivateKey(rsa);\n                }\n\n                string UriPrefix = server.Url.AbsoluteUri;\n\n                Uri url = new($\"{UriPrefix}timestamp/{certificateWithPrivateKey.Thumbprint}\");\n\n                TimestampService timestampService = new(certificateAuthority, certificateWithPrivateKey, url);\n\n                timestampService._disposable = server.RegisterResponder(timestampService);\n\n                return timestampService;\n            }\n        }\n\n        public override async Task RespondAsync(HttpContext context)\n        {\n            RequestAndResponse reqAndResp = new();\n\n            try\n            {\n                reqAndResp.RequestContentType = context.Request.ContentType;\n\n                if (!string.Equals(context.Request.ContentType, RequestContentType, StringComparison.OrdinalIgnoreCase))\n                {\n                    context.Response.StatusCode = 400;\n                    reqAndResp.ResponseStatus = 400;\n\n                    return;\n                }\n\n                byte[] bytes = ReadRequestBody(context.Request);\n\n                reqAndResp.RequestBody = Convert.ToBase64String(bytes);\n\n                if (!Rfc3161TimestampRequest.TryDecode(bytes, out Rfc3161TimestampRequest? request, out int _))\n                {\n                    context.Response.StatusCode = 400;\n                    reqAndResp.ResponseStatus = 400;\n\n                    return;\n                }\n\n                reqAndResp.Request = request;\n\n                ReadOnlyMemory<byte> response;\n\n                if (request.HashAlgorithmId.IsEqualTo(Oids.Sha1))\n                {\n                    response = CreateResponse(PkiStatus.Rejection, signedCms: null);\n                }\n                else\n                {\n                    ReadOnlyMemory<byte> tstInfo = CreateTstInfo(\n                        request.HashAlgorithmId,\n                        request.GetMessageHash(),\n                        _nextSerialNumber,\n                        request.GetNonce());\n\n                    ++_nextSerialNumber;\n\n                    SignedCms timestamp = GenerateTimestamp(request!, tstInfo);\n                    response = CreateResponse(PkiStatus.Granted, timestamp);\n                }\n\n                context.Response.ContentType = ResponseContentType;\n                context.Response.StatusCode = 200;\n\n                reqAndResp.ResponseStatus = 200;\n                reqAndResp.ResponseBody = Convert.ToBase64String(response.Span);\n\n                WriteResponseBody(context.Response, response);\n            }\n            catch (Exception ex)\n            {\n                reqAndResp.Exception = ex;\n            }\n            finally\n            {\n                await WriteAsync(reqAndResp);\n            }\n        }\n\n        private async Task WriteAsync(RequestAndResponse reqAndResp)\n        {\n            string filePath = Path.Combine(\n                _temporaryDirectory.Directory.FullName,\n                $\"TimestampServer_{DateTimeOffset.UtcNow:yyyyMMdd-HHmmss.fffffffZ}_{Guid.NewGuid():N}.txt\");\n            FileInfo file = new(filePath);\n\n            await using (FileStream stream = file.OpenWrite())\n            await using (StreamWriter writer = new(stream))\n            {\n                await writer.WriteAsync($\"Request Content-Type:  \");\n                await writer.WriteLineAsync(reqAndResp.RequestContentType);\n                await writer.WriteAsync($\"Request body:  \");\n                await writer.WriteLineAsync(reqAndResp.RequestBody);\n\n                if (reqAndResp.Request is not null)\n                {\n                    await writer.WriteAsync($\"Request version:  \");\n                    await writer.WriteLineAsync(reqAndResp.Request.Version.ToString());\n                    await writer.WriteAsync($\"Request hash algorithm OID:  \");\n                    await writer.WriteLineAsync(reqAndResp.Request.HashAlgorithmId.Value);\n                    await writer.WriteAsync($\"Request requested policy OID:  \");\n                    await writer.WriteLineAsync(reqAndResp.Request.RequestedPolicyId?.Value);\n                    await writer.WriteAsync($\"Request request signer certificate:  \");\n                    await writer.WriteLineAsync(reqAndResp.Request.RequestSignerCertificate.ToString());\n                    await writer.WriteAsync($\"Request has extensions:  \");\n                    await writer.WriteLineAsync(reqAndResp.Request.HasExtensions.ToString());\n                }\n\n                await writer.WriteAsync($\"Response status:  \");\n                await writer.WriteLineAsync(reqAndResp.ResponseStatus?.ToString());\n                await writer.WriteAsync($\"Response body:  \");\n                await writer.WriteLineAsync(reqAndResp.ResponseBody);\n                await writer.WriteAsync($\"Exception:  \");\n                await writer.WriteLineAsync(reqAndResp.Exception?.ToString());\n            }\n        }\n\n        private SignedCms GenerateTimestamp(Rfc3161TimestampRequest request, ReadOnlyMemory<byte> tstInfo)\n        {\n            ArgumentNullException.ThrowIfNull(request, nameof(request));\n\n            ContentInfo contentInfo = new(Oids.TSTInfoContentType, tstInfo.ToArray());\n            SignedCms signedCms = new(contentInfo);\n            CmsSigner signer = new(SubjectIdentifierType.SubjectKeyIdentifier, Certificate);\n\n            signer.IncludeOption = request.RequestSignerCertificate ? X509IncludeOption.EndCertOnly : X509IncludeOption.None;\n            signer.DigestAlgorithm = Oids.Sha256;\n\n            CryptographicAttributeObject signingCertificateV2 = AttributeUtility.CreateSigningCertificateV2Attribute(Certificate, HashAlgorithmName.SHA256);\n\n            signer.SignedAttributes.Add(signingCertificateV2);\n\n            signedCms.ComputeSignature(signer, silent: true);\n\n            return signedCms;\n        }\n\n        private static ReadOnlyMemory<byte> CreateTstInfo(\n            Oid hashAlgorithmId,\n            ReadOnlyMemory<byte> messageHash,\n            BigInteger serialNumber,\n            ReadOnlyMemory<byte>? nonce)\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence())\n            {\n                writer.WriteInteger(1);  // version\n                writer.WriteObjectIdentifier(Oids.TestCertPolicyOne.Value!); // policy\n\n                using (writer.PushSequence()) // messageImprint\n                {\n                    AlgorithmIdentifier algorithmIdentifier = new(hashAlgorithmId);\n\n                    writer.WriteEncodedValue(algorithmIdentifier.Encode().Span);\n                    writer.WriteOctetString(messageHash.Span);\n                }\n\n                writer.WriteInteger(serialNumber); // serialNumber\n                writer.WriteGeneralizedTime(DateTimeOffset.Now, omitFractionalSeconds: true); // genTime\n\n                using (writer.PushSequence()) // accuracy\n                {\n                    writer.WriteInteger(1); // seconds\n                }\n\n                writer.WriteBoolean(false); // ordering\n\n                if (nonce is not null)\n                {\n                    writer.WriteInteger(nonce.Value.Span);\n                }\n            }\n\n            return writer.Encode();\n        }\n\n        // See https://datatracker.ietf.org/doc/html/rfc3161#section-2.4.2\n        private static ReadOnlyMemory<byte> CreateResponse(PkiStatus pkiStatus, SignedCms? signedCms)\n        {\n            AsnWriter writer = new(AsnEncodingRules.DER);\n\n            using (writer.PushSequence()) // TimeStampResp\n            {\n                using (writer.PushSequence()) // PKIStatusInfo\n                {\n                    writer.WriteInteger((long)pkiStatus);\n                }\n\n                if (signedCms is not null)\n                {\n                    byte[] encodedCms = signedCms.Encode();\n\n                    writer.WriteEncodedValue(encodedCms);\n                }\n            }\n\n            return writer.Encode();\n        }\n\n        private enum PkiStatus\n        {\n            Granted = 0,\n            GrantedWithMods = 1,\n            Rejection = 2,\n            Waiting = 3,\n            RevocationWarning = 4,\n            RevocationNotification = 5\n        }\n\n        private enum PkiFailureInfo\n        {\n            BadAlg = 0,\n            BadRequest = 2,\n            BadDataFormat = 5,\n            timeNotAvailable = 14,\n            unacceptedPolicy = 15,\n            unacceptedExtension = 16,\n            addInfoNotAvailable = 17,\n            systemFailure = 25\n        }\n\n        private sealed class RequestAndResponse\n        {\n            internal string? RequestContentType { get; set; }\n            internal string? RequestBody { get; set; }\n            internal Rfc3161TimestampRequest? Request { get; set; }\n            internal Exception? Exception { get; set; }\n            internal int? ResponseStatus { get; set; }\n            internal string? ResponseBody { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/SignerSpy.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\nusing Moq;\n\nnamespace Sign.Core.Test\n{\n    internal sealed class SignerSpy : IDataFormatSigner, IDefaultDataFormatSigner\n    {\n        private readonly List<IDataFormatSigner> _providers;\n        private readonly List<FileInfo> _signedFiles = new();\n\n        public IDataFormatSigner Signer { get; }\n\n        internal IReadOnlyList<FileInfo> SignedFiles\n        {\n            get => _signedFiles;\n        }\n\n        internal SignerSpy()\n        {\n            ISignatureAlgorithmProvider signatureAlgorithmProvider = Mock.Of<ISignatureAlgorithmProvider>();\n            ICertificateProvider certificateProvider = Mock.Of<ICertificateProvider>();\n            ILogger<IDataFormatSigner> logger = Mock.Of<ILogger<IDataFormatSigner>>();\n            IMageCli mageCli = Mock.Of<IMageCli>();\n            IManifestSigner manifestSigner = Mock.Of<IManifestSigner>();\n            INuGetSignTool nuGetSignTool = Mock.Of<INuGetSignTool>();\n            IVsixSignTool openVsixSignTool = Mock.Of<IVsixSignTool>();\n            IServiceProvider serviceProvider = Mock.Of<IServiceProvider>();\n            IToolConfigurationProvider toolConfigurationProvider = Mock.Of<IToolConfigurationProvider>();\n            IFileMatcher fileMatcher = Mock.Of<IFileMatcher>();\n\n            Signer = new AzureSignToolSigner(\n                toolConfigurationProvider,\n                signatureAlgorithmProvider,\n                certificateProvider,\n                logger);\n\n            _providers = new List<IDataFormatSigner>()\n            {\n                new AppInstallerServiceSigner(certificateProvider, logger),\n                Signer,\n                new ClickOnceSigner(\n                    signatureAlgorithmProvider,\n                    certificateProvider,\n                    serviceProvider,\n                    mageCli,\n                    manifestSigner,\n                    logger,\n                    fileMatcher),\n                new NuGetSigner(signatureAlgorithmProvider, certificateProvider, nuGetSignTool, logger),\n                new VsixSigner(signatureAlgorithmProvider, certificateProvider, openVsixSignTool, logger)\n            };\n        }\n\n        public bool CanSign(FileInfo file)\n        {\n            return _providers.Any(provider => provider.CanSign(file));\n        }\n\n        public Task SignAsync(IEnumerable<FileInfo> files, SignOptions options)\n        {\n            _signedFiles.AddRange(files);\n\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/TestInfrastructure/TemporaryEnvironmentPathOverride.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    internal sealed class TemporaryEnvironmentPathOverride : IDisposable\n    {\n        private const string Name = \"PATH\";\n\n        private readonly string? _originalEnvironmentPath;\n\n        internal TemporaryEnvironmentPathOverride(string path)\n        {\n            _originalEnvironmentPath = Environment.GetEnvironmentVariable(Name);\n\n            string paths = _originalEnvironmentPath ?? string.Empty;\n            string newPaths = string.Join(Path.PathSeparator, paths, path);\n\n            Environment.SetEnvironmentVariable(Name, newPaths);\n        }\n\n        public void Dispose()\n        {\n            Environment.SetEnvironmentVariable(Name, _originalEnvironmentPath);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Tools/ToolConfigurationProviderTests.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class ToolConfigurationProviderTests\n    {\n        private static readonly AppRootDirectoryLocator DirectoryLocator = new();\n        private readonly ToolConfigurationProvider _provider = new(DirectoryLocator);\n        private readonly DirectoryInfo _rootDirectory = DirectoryLocator.Directory!;\n\n        [Fact]\n        public void Constructor_WhenAppRootDirectoryLocatorIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ToolConfigurationProvider(appRootDirectoryLocator: null!));\n\n            Assert.Equal(\"appRootDirectoryLocator\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Mage_Always_ReturnsFile()\n        {\n            string expectedFilePath = Path.Combine(_rootDirectory.FullName, \"tools\", \"SDK\", \"x86\", \"mage.exe\");\n\n            Assert.Equal(expectedFilePath, _provider.Mage.FullName);\n        }\n\n        [Fact]\n        public void MakeAppx_Always_ReturnsFile()\n        {\n            string expectedFilePath = Path.Combine(_rootDirectory.FullName, \"tools\", \"SDK\", \"x64\", \"makeappx.exe\");\n\n            Assert.Equal(expectedFilePath, _provider.MakeAppx.FullName);\n        }\n\n        [Fact]\n        public void SignToolManifest_Always_ReturnsFile()\n        {\n            string expectedFilePath = Path.Combine(_rootDirectory.FullName, \"tools\", \"SDK\", \"x64\", \"SignTool.exe.manifest\");\n\n            Assert.Equal(expectedFilePath, _provider.SignToolManifest.FullName);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/CertificateSigningContextTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public class CertificateSigningContextTests\n    {\n        private readonly PfxFilesFixture _pfxFilesFixture;\n\n        public CertificateSigningContextTests(PfxFilesFixture pfxFilesFixture)\n        {\n            ArgumentNullException.ThrowIfNull(pfxFilesFixture, nameof(pfxFilesFixture));\n\n            _pfxFilesFixture = pfxFilesFixture;\n        }\n\n        public static IEnumerable<object[]> RsaCertificates\n        {\n            get\n            {\n                yield return new object[] { 2048, HashAlgorithmName.SHA256, };\n                yield return new object[] { 3072, HashAlgorithmName.SHA384 };\n            }\n        }\n\n        [Theory]\n        [MemberData(nameof(RsaCertificates))]\n        public void ShouldSignABlobOfDataWithRsaSha256(int keySizeInBits, HashAlgorithmName hashAlgorithmName)\n        {\n            using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits, hashAlgorithmName))\n            using (RSA? privateKey = certificate.GetRSAPrivateKey())\n            {\n                var config = new SignConfigurationSet\n                (\n                    publicCertificate: certificate,\n                    signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                    fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                    signingKey: privateKey!\n                );\n\n                var context = new SigningContext(config);\n                using (var hash = SHA256.Create())\n                {\n                    byte[] digest = hash.ComputeHash(new byte[] { 1, 2, 3 });\n                    byte[] signature = context.SignDigest(digest);\n                    Assert.Equal(OpcKnownUris.SignatureAlgorithms.RsaSHA256, context.XmlDSigIdentifier);\n                    Assert.Equal(SigningAlgorithm.RSA, context.SignatureAlgorithm);\n\n                    bool roundtrips = context.VerifyDigest(digest, signature);\n                    Assert.True(roundtrips);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/Crypt32Tests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.ComponentModel;\nusing System.Runtime.InteropServices;\nusing Sign.Core.Interop;\nusing Xunit.Abstractions;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public class Crypt32Tests\n    {\n        private readonly CertificatesFixture _certificatesFixture;\n        private readonly ITestOutputHelper _testOutputHelper;\n\n        public Crypt32Tests(CertificatesFixture certificatesFixture, ITestOutputHelper testOutputHelper)\n        {\n            ArgumentNullException.ThrowIfNull(certificatesFixture, nameof(certificatesFixture));\n            ArgumentNullException.ThrowIfNull(testOutputHelper, nameof(testOutputHelper));\n\n            _certificatesFixture = certificatesFixture;\n            _testOutputHelper = testOutputHelper;\n        }\n\n        [Fact]\n        public void ShouldTimestampData()\n        {\n            var data = new byte[] { 1, 2, 3 };\n            var parameters = new CRYPT_TIMESTAMP_PARA\n            {\n                cExtension = 0,\n                fRequestCerts = true,\n                pszTSAPolicyId = null\n            };\n\n            bool ok = Crypt32.CryptRetrieveTimeStamp(_certificatesFixture.TimestampServiceUrl.AbsoluteUri, CryptRetrieveTimeStampRetrievalFlags.NONE, 30 * 1000, Oids.Sha512.Value, ref parameters, data, (uint)data.Length, out var pointer, IntPtr.Zero, IntPtr.Zero);\n            // Capture the last P/Invoke error and throw later.\n            Win32Exception exception = new();\n\n            if (!ok)\n            {\n                throw exception;\n            }\n\n            bool success = false;\n            try\n            {\n                pointer.DangerousAddRef(ref success);\n                Assert.True(success);\n                var structure = Marshal.PtrToStructure<CRYPT_TIMESTAMP_CONTEXT>(pointer.DangerousGetHandle());\n                var encoded = new byte[structure.cbEncoded];\n                Marshal.Copy(structure.pbEncoded, encoded, 0, encoded.Length);\n            }\n            finally\n            {\n                if (success)\n                {\n                    pointer.DangerousRelease();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/HexHelperTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class HexHelperTests\n    {\n        [Theory]\n        [InlineData(new byte[] { }, \"\")]\n        [InlineData(new byte[] { 0 }, \"00\")]\n        [InlineData(new byte[] { 0, 0, 0, 1 }, \"00000001\")]\n        [InlineData(new byte[] { 0, 255, 1, 254 }, \"00FF01FE\")]\n        public void TryHexEncode_WhenInputsAreValid_ReturnsTrue(byte[] input, string expected)\n        {\n            Span<char> buffer = stackalloc char[expected.Length];\n            Assert.True(HexHelpers.TryHexEncode(input, buffer));\n            Assert.Equal(expected, buffer.ToString());\n        }\n\n        [Fact]\n        public void TryHexEncode_WhenBufferIsTooSmall_ReturnsFalse()\n        {\n            Span<char> buffer = stackalloc char[1];\n            Assert.False(HexHelpers.TryHexEncode(new byte[2], buffer));\n        }\n\n        [Fact]\n        public void TryHexEncode_Never_ClobbersSurroundingData()\n        {\n            Span<char> buffer = stackalloc char[] { 'Q', 'Q', 'Q', 'Q' };\n            Assert.True(HexHelpers.TryHexEncode(new byte[] { 0x66 }, buffer.Slice(1, 2)));\n            Assert.Equal(\"Q66Q\", buffer.ToString());\n        }\n\n        [Fact]\n        public void TryHexEncode_WithAnyByteValue_ReturnsTrue()\n        {\n            Span<char> buffer = stackalloc char[2];\n            Span<byte> value = stackalloc byte[1];\n            for (var i = 0; i <= 0xFF; i++)\n            {\n                value[0] = (byte)i;\n                Assert.True(HexHelpers.TryHexEncode(value, buffer));\n                Assert.Equal(i.ToString(\"X2\"), buffer.ToString());\n            }\n        }\n\n        [Theory]\n        [InlineData(null)]\n        [InlineData(\"\")]\n        [InlineData(\" \")]\n        [InlineData(\"g\")]\n        public void IsHex_WhenTextIsNotHex_ReturnsFalse(string? text)\n        {\n            Assert.False(HexHelpers.IsHex(text));\n        }\n\n        [Fact]\n        public void IsHex_WhenTextIsHex_ReturnsTrue()\n        {\n            Assert.True(HexHelpers.IsHex(\"0123456789abcdefABCDEF\"));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/OpcPackageSigningTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Xml;\nusing Sign.Core.Timestamp;\nusing Xunit.Abstractions;\n\nnamespace Sign.Core.Test\n{\n    [Collection(SigningTestsCollection.Name)]\n    public sealed class OpcPackageSigningTests : IDisposable\n    {\n        private static readonly string SamplePackage = Path.Combine(\".\", \"TestAssets\", \"VSIXSamples\", \"OpenVsixSignToolTest.vsix\");\n        private readonly List<string> _shadowFiles = new List<string>();\n\n        private readonly CertificatesFixture _certificatesFixture;\n        private readonly PfxFilesFixture _pfxFilesFixture;\n        private readonly ITestOutputHelper _testOutputHelper;\n\n        public OpcPackageSigningTests(\n            CertificatesFixture certificatesFixture,\n            PfxFilesFixture pfxFilesFixture,\n            ITestOutputHelper testOutputHelper)\n        {\n            ArgumentNullException.ThrowIfNull(certificatesFixture, nameof(certificatesFixture));\n            ArgumentNullException.ThrowIfNull(pfxFilesFixture, nameof(pfxFilesFixture));\n            ArgumentNullException.ThrowIfNull(testOutputHelper, nameof(testOutputHelper));\n\n            _certificatesFixture = certificatesFixture;\n            _pfxFilesFixture = pfxFilesFixture;\n            _testOutputHelper = testOutputHelper;\n        }\n\n        [Theory]\n        [MemberData(nameof(RsaSigningTheories))]\n        public void ShouldSignFileWithRsa(int keySizeInBits, HashAlgorithmName hashAlgorithmName, HashAlgorithmName fileDigestAlgorithm, string expectedAlgorithm)\n        {\n            _ = expectedAlgorithm;\n\n            using (OpcPackage package = ShadowCopyPackage(SamplePackage, out string path, OpcPackageFileMode.ReadWrite))\n            {\n                OpcPackageSignatureBuilder builder = package.CreateSignatureBuilder();\n                builder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n\n                using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits, hashAlgorithmName))\n                using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n                {\n                    OpcSignature result = builder.Sign(\n                        new SignConfigurationSet(\n                            publicCertificate: certificate,\n                            signatureDigestAlgorithm: fileDigestAlgorithm,\n                            fileDigestAlgorithm: fileDigestAlgorithm,\n                            signingKey: rsaPrivateKey!));\n                    Assert.NotNull(result);\n                }\n            }\n        }\n\n        public static IEnumerable<object[]> RsaSigningTheories\n        {\n            get\n            {\n                yield return new object[] { 2048, HashAlgorithmName.SHA256, HashAlgorithmName.SHA512, OpcKnownUris.SignatureAlgorithms.RsaSHA512.AbsoluteUri };\n                yield return new object[] { 2048, HashAlgorithmName.SHA256, HashAlgorithmName.SHA384, OpcKnownUris.SignatureAlgorithms.RsaSHA384.AbsoluteUri };\n                yield return new object[] { 2048, HashAlgorithmName.SHA256, HashAlgorithmName.SHA256, OpcKnownUris.SignatureAlgorithms.RsaSHA256.AbsoluteUri };\n            }\n        }\n\n        [Theory]\n        [MemberData(nameof(RsaTimestampTheories))]\n        public async Task ShouldTimestampFileWithRsa(int keySizeInBits, HashAlgorithmName hashAlgorithmName, HashAlgorithmName timestampDigestAlgorithm)\n        {\n            using (OpcPackage package = ShadowCopyPackage(SamplePackage, out var path, OpcPackageFileMode.ReadWrite))\n            {\n                OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n\n                using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits, hashAlgorithmName))\n                using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n                {\n                    OpcSignature signature = signerBuilder.Sign(\n                        new SignConfigurationSet(\n                            publicCertificate: certificate,\n                            signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                            fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                            signingKey: rsaPrivateKey!));\n                    OpcPackageTimestampBuilder timestampBuilder = signature.CreateTimestampBuilder();\n                    TimestampResult result = await timestampBuilder.SignAsync(_certificatesFixture.TimestampServiceUrl, timestampDigestAlgorithm);\n\n                    Assert.Equal(TimestampResult.Success, result);\n                }\n            }\n        }\n\n        [Fact]\n        public void ShouldSupportReSigning()\n        {\n            string path;\n            using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits: 2048, HashAlgorithmName.SHA256))\n            using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n            {\n                using (OpcPackage package = ShadowCopyPackage(SamplePackage, out path, OpcPackageFileMode.ReadWrite))\n                {\n                    OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                    signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n                    signerBuilder.Sign(\n                        new SignConfigurationSet(\n                            publicCertificate: certificate,\n                            signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                            fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                            signingKey: rsaPrivateKey!));\n                }\n                using (OpcPackage package = OpcPackage.Open(path, OpcPackageFileMode.ReadWrite))\n                {\n                    OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                    signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n                    signerBuilder.Sign(\n                        new SignConfigurationSet(\n                            publicCertificate: certificate,\n                            signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                            fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                            signingKey: rsaPrivateKey!));\n                }\n            }\n            using (OpcPackage netfxPackage = OpcPackage.Open(path))\n            {\n                Assert.NotEmpty(netfxPackage.GetSignatures());\n            }\n        }\n\n        [Fact]\n        public void ShouldSupportReSigningWithDifferentCertificate()\n        {\n            string path;\n\n            using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits: 2048, HashAlgorithmName.SHA256))\n            using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n            using (OpcPackage package = ShadowCopyPackage(SamplePackage, out path, OpcPackageFileMode.ReadWrite))\n            {\n                OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n                signerBuilder.Sign(\n                    new SignConfigurationSet(\n                        publicCertificate: certificate,\n                        signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                        fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                        signingKey: rsaPrivateKey!));\n            }\n\n            using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits: 3072, HashAlgorithmName.SHA384))\n            using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n            using (OpcPackage package = OpcPackage.Open(path, OpcPackageFileMode.ReadWrite))\n            {\n                OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n                signerBuilder.Sign(\n                    new SignConfigurationSet(\n                        publicCertificate: certificate,\n                        signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                        fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                        signingKey: rsaPrivateKey!));\n            }\n            using (var netfxPackage = OpcPackage.Open(path))\n            {\n                Assert.NotEmpty(netfxPackage.GetSignatures());\n            }\n        }\n\n        [Fact]\n        public void ShouldRemoveSignature()\n        {\n            string path;\n            using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(keySizeInBits: 2048, HashAlgorithmName.SHA256))\n            using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n            using (OpcPackage package = ShadowCopyPackage(SamplePackage, out path, OpcPackageFileMode.ReadWrite))\n            {\n                OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n                signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n                signerBuilder.Sign(\n                    new SignConfigurationSet(\n                        publicCertificate: certificate,\n                        signatureDigestAlgorithm: HashAlgorithmName.SHA256,\n                        fileDigestAlgorithm: HashAlgorithmName.SHA256,\n                        signingKey: rsaPrivateKey!));\n            }\n            using (OpcPackage package = OpcPackage.Open(path, OpcPackageFileMode.ReadWrite))\n            {\n                List<OpcSignature> signatures = package.GetSignatures().ToList();\n                Assert.Single(signatures);\n                OpcSignature signature = signatures[0];\n                signature.Remove();\n                Assert.Null(signature.Part);\n                Assert.Throws<InvalidOperationException>(() => signature.CreateTimestampBuilder());\n                Assert.Empty(package.GetSignatures());\n            }\n        }\n\n        [Fact]\n        public void ShouldUseInvariantCultureForContextCreationTime()\n        {\n            CultureInfo originalCulture = CultureInfo.CurrentCulture;\n\n            try\n            {\n                // This test only works if the current culture is one of a set of cultures that includes en-DK that\n                // that repro the original bug.  However, because tests should not rely on a specific culture being\n                // installed, we'll create a custom culture just for this test.\n                var customCulture = (CultureInfo)CultureInfo.InvariantCulture.Clone();\n\n                customCulture.DateTimeFormat.TimeSeparator = \".\";\n\n                CultureInfo.CurrentCulture = customCulture;\n\n                using (OpcPackage package = ShadowCopyPackage(\n                    SamplePackage,\n                    out string? path,\n                    OpcPackageFileMode.ReadWrite))\n                {\n                    OpcPackageSignatureBuilder signerBuilder = package.CreateSignatureBuilder();\n\n                    signerBuilder.EnqueueNamedPreset<VSIXSignatureBuilderPreset>();\n\n                    using (X509Certificate2 certificate = _pfxFilesFixture.GetPfx(\n                        keySizeInBits: 3072,\n                        HashAlgorithmName.SHA384))\n                    using (RSA? rsaPrivateKey = certificate.GetRSAPrivateKey())\n                    {\n                        OpcSignature signature = signerBuilder.Sign(\n                            new SignConfigurationSet(\n                                publicCertificate: certificate,\n                                signatureDigestAlgorithm: HashAlgorithmName.SHA384,\n                                fileDigestAlgorithm: HashAlgorithmName.SHA384,\n                                signingKey: rsaPrivateKey!));\n\n                        using (Stream stream = signature.Part!.Open())\n                        {\n                            XmlDocument document = new();\n\n                            document.Load(stream);\n\n                            XmlNode? signatureTimeValueElement = document.GetElementsByTagName(\"Value\")[0];\n\n                            Assert.NotNull(signatureTimeValueElement);\n\n                            const string expectedFormat = \"yyyy-MM-ddTHH:mm:ss.fzzz\";\n\n                            bool isValidFormat = DateTimeOffset.TryParseExact(\n                                signatureTimeValueElement.InnerText,\n                                expectedFormat,\n                                CultureInfo.InvariantCulture,\n                                DateTimeStyles.None,\n                                out DateTimeOffset parsedDateTime);\n\n                            Assert.True(isValidFormat, $\"The date time string '{signatureTimeValueElement.InnerText}' does not match the expected format '{expectedFormat}'.\");\n                        }\n                    }\n                }\n            }\n            finally\n            {\n                CultureInfo.CurrentCulture = originalCulture;\n            }\n        }\n\n        public static IEnumerable<object[]> RsaTimestampTheories\n        {\n            get\n            {\n                yield return new object[] { 2048, HashAlgorithmName.SHA256, HashAlgorithmName.SHA256 };\n            }\n        }\n\n        private OpcPackage ShadowCopyPackage(string packagePath, out string path, OpcPackageFileMode mode = OpcPackageFileMode.Read)\n        {\n            string temp = Path.GetTempFileName();\n            _shadowFiles.Add(temp);\n            File.Copy(packagePath, temp, overwrite: true);\n            path = temp;\n            return OpcPackage.Open(temp, mode);\n        }\n\n        public void Dispose()\n        {\n            void CleanUpShadows()\n            {\n                _shadowFiles.ForEach(File.Delete);\n            }\n            CleanUpShadows();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/OpcPackageTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class OpcPackageTests : IDisposable\n    {\n        private static readonly string SamplePackage = Path.Combine(\".\", \"TestAssets\", \"VSIXSamples\", \"OpenVsixSignToolTest.vsix\");\n        private static readonly string SamplePackageSigned = Path.Combine(\".\", \"TestAssets\", \"VSIXSamples\", \"OpenVsixSignToolTest-Signed.vsix\");\n        private readonly List<string> _shadowFiles = new List<string>();\n\n        [Fact]\n        public void ShouldOpenAndDisposeAPackageAndDisposeIsIdempotent()\n        {\n            var package = OpcPackage.Open(SamplePackage);\n            package.Dispose();\n            package.Dispose();\n        }\n\n        [Fact]\n        public void ShouldReadContentTypes()\n        {\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                Assert.Equal(4, package.ContentTypes.Count);\n                var first = package.ContentTypes[0];\n                Assert.Equal(\"vsixmanifest\", first.Extension);\n                Assert.Equal(\"text/xml\", first.ContentType);\n                Assert.Equal(OpcContentTypeMode.Default, first.Mode);\n            }\n        }\n\n        [Fact]\n        public void ShouldNotAllowUpdatingContentTypesInReadOnly()\n        {\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                var newItem = new OpcContentType(\"test\", \"test\", OpcContentTypeMode.Default);\n                var contentTypes = package.ContentTypes;\n                Assert.Throws<InvalidOperationException>(() => contentTypes.Add(newItem));\n            }\n        }\n\n        [Fact]\n        public void ShouldAllowUpdatingContentType()\n        {\n            int initialCount;\n            string shadowPath;\n            using (var package = ShadowCopyPackage(SamplePackage, out shadowPath, OpcPackageFileMode.ReadWrite))\n            {\n                initialCount = package.ContentTypes.Count;\n                var newItem = new OpcContentType(\"test\", \"application/test\", OpcContentTypeMode.Default);\n                package.ContentTypes.Add(newItem);\n            }\n            using (var reopenedPackage = OpcPackage.Open(shadowPath))\n            {\n                Assert.Equal(initialCount + 1, reopenedPackage.ContentTypes.Count);\n            }\n        }\n\n        [Fact]\n        public void ShouldAllowUpdatingRelationships()\n        {\n            int initialCount;\n            string shadowPath;\n            using (var package = ShadowCopyPackage(SamplePackage, out shadowPath, OpcPackageFileMode.ReadWrite))\n            {\n                initialCount = package.Relationships.Count;\n                var newItem = new OpcRelationship(new Uri(\"/test\", UriKind.RelativeOrAbsolute), new Uri(\"/test\", UriKind.RelativeOrAbsolute));\n                package.Relationships.Add(newItem);\n                Assert.True(newItem.Id != null && newItem.Id.Length == 9);\n            }\n            using (var reopenedPackage = OpcPackage.Open(shadowPath))\n            {\n                Assert.Equal(initialCount + 1, reopenedPackage.Relationships.Count);\n            }\n        }\n\n        [Fact]\n        public void ShouldRemovePart()\n        {\n            using (var package = ShadowCopyPackage(SamplePackage, out _, OpcPackageFileMode.ReadWrite))\n            {\n                var partToRemove = new Uri(\"/extension.vsixmanifest\", UriKind.Relative);\n                var part = package.GetPart(partToRemove);\n                Assert.NotNull(part);\n                package.RemovePart(part);\n                Assert.Null(package.GetPart(partToRemove));\n            }\n        }\n\n\n        [Fact]\n        public void ShouldRemoveRelationshipsForRemovedPartWhereRelationshipIsMaterialized()\n        {\n            string path;\n            using (var package = ShadowCopyPackage(SamplePackage, out path, OpcPackageFileMode.ReadWrite))\n            {\n                var partToRemove = new Uri(\"/extension.vsixmanifest\", UriKind.Relative);\n                var part = package.GetPart(partToRemove);\n                part!.Relationships.Add(new OpcRelationship(new Uri(\"/test\", UriKind.Relative), new Uri(\"http://test.com\", UriKind.Absolute)));\n            }\n            using (var package = OpcPackage.Open(path, OpcPackageFileMode.ReadWrite))\n            {\n                var relationshipPartUri = new Uri(\"/_rels/extension.vsixmanifest.rels\", UriKind.Relative);\n                Assert.NotNull(package.GetPart(relationshipPartUri));\n                var partToRemove = new Uri(\"/extension.vsixmanifest\", UriKind.Relative);\n                var part = package.GetPart(partToRemove);\n                package.RemovePart(part!);\n                Assert.False(package.HasPart(relationshipPartUri));\n                Assert.Null(package.GetPart(relationshipPartUri));\n            }\n        }\n\n        [Fact]\n        public void ShouldRemoveRelationshipsForRemovedPartWhereRelationshipIsNotMaterialized()\n        {\n            string path;\n            using (var package = ShadowCopyPackage(SamplePackage, out path, OpcPackageFileMode.ReadWrite))\n            {\n                var partToRemove = new Uri(\"/extension.vsixmanifest\", UriKind.Relative);\n                var part = package.GetPart(partToRemove);\n                part!.Relationships.Add(new OpcRelationship(new Uri(\"/test\", UriKind.Relative), new Uri(\"http://test.com\", UriKind.Absolute)));\n                package.RemovePart(part);\n            }\n            using (var package = OpcPackage.Open(path))\n            {\n                var relationshipPartUri = new Uri(\"/_rels/extension.vsixmanifest.rels\", UriKind.Relative);\n                Assert.False(package.HasPart(relationshipPartUri));\n                Assert.Null(package.GetPart(relationshipPartUri));\n            }\n        }\n\n        [Fact]\n        public void ShouldEnumerateAllParts()\n        {\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                var parts = package.GetParts().ToArray();\n                Assert.Equal(2, parts.Length);\n            }\n        }\n\n        [Fact]\n        public void ShouldCreateSignatureBuilder()\n        {\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                var builder = package.CreateSignatureBuilder();\n                foreach (var part in package.GetParts())\n                {\n                    builder.EnqueuePart(part);\n                    Assert.True(builder.DequeuePart(part));\n                }\n            }\n        }\n\n        [Theory]\n        [InlineData(\"extension.vsixmanifest\")]\n        [InlineData(\"/extension.vsixmanifest\")]\n        [InlineData(\"package:///extension.vsixmanifest\")]\n        public void ShouldOpenSinglePartByRelativeUri(string uri)\n        {\n            var partUri = new Uri(uri, UriKind.RelativeOrAbsolute);\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                Assert.NotNull(package.GetPart(partUri));\n            }\n        }\n\n        [Fact]\n        public void ShouldReturnEmptyEnumerableForNoSignatureOriginRelationship()\n        {\n            using (var package = OpcPackage.Open(SamplePackage))\n            {\n                Assert.Empty(package.GetSignatures());\n            }\n        }\n\n        [Fact]\n        public void ShouldReturnSignatureForSignedPackage()\n        {\n            using (var package = OpcPackage.Open(SamplePackageSigned))\n            {\n                Assert.NotEmpty(package.GetSignatures());\n            }\n        }\n\n        private OpcPackage ShadowCopyPackage(string packagePath, out string path, OpcPackageFileMode mode = OpcPackageFileMode.Read)\n        {\n            var temp = Path.GetTempFileName();\n            _shadowFiles.Add(temp);\n            File.Copy(packagePath, temp, true);\n            path = temp;\n            return OpcPackage.Open(temp, mode);\n        }\n\n        public void Dispose()\n        {\n            void CleanUpShadows()\n            {\n                _shadowFiles.ForEach(File.Delete);\n            }\n            CleanUpShadows();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Tools/VSIXSignTool/UriHelpersTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.Core.Test\n{\n    public class UriHelpersTests\n    {\n        [Theory]\n        [InlineData(\"package:///file.bin\", \"file.bin\")]\n        [InlineData(\"package:/file.bin\", \"file.bin\")]\n        [InlineData(\"package:///sub/file.bin\", \"sub/file.bin\")]\n        [InlineData(\"package:/sub/file.bin\", \"sub/file.bin\")]\n        [InlineData(\"package:///sub/file.bin?query=string\", \"sub/file.bin\")]\n        [InlineData(\"package:/sub/file.bin?query=string\", \"sub/file.bin\")]\n        public void ShouldHandlePackagePathForRelativeUris(string uri, string expected)\n        {\n            var part = new Uri(uri, UriKind.Absolute);\n            var packagePath = part.ToPackagePath();\n            Assert.Equal(expected, packagePath);\n        }\n\n        [Theory]\n        [InlineData(\"package:///file.bin\", \"/file.bin\")]\n        [InlineData(\"package:/file.bin\", \"/file.bin\")]\n        [InlineData(\"package:///sub/file.bin\", \"/sub/file.bin\")]\n        [InlineData(\"package:/sub/file.bin\", \"/sub/file.bin\")]\n        [InlineData(\"package:///sub/file.bin?query=string\", \"/sub/file.bin?query=string\")]\n        [InlineData(\"package:/sub/file.bin?query=string\", \"/sub/file.bin?query=string\")]\n        public void ShouldHandleReferencePathForRelativeUris(string uri, string expected)\n        {\n            var part = new Uri(uri, UriKind.Absolute);\n            var packagePath = part.ToQualifiedPath();\n            Assert.Equal(expected, packagePath);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.Core.Test/Usings.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nglobal using Xunit;"
  },
  {
    "path": "test/Sign.SignatureProviders.ArtifactSigning.Test/RSATrustedSigningTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Azure;\nusing Azure.CodeSigning;\nusing Azure.CodeSigning.Models;\nusing Moq;\nusing Moq.Protected;\nusing Sign.SignatureProviders.ArtifactSigning;\n\nnamespace Sign.SignatureProviders.KeyVault.Test\n{\n    public class RSATrustedSigningTests\n    {\n        private static readonly string AccountName = \"testAccount\";\n        private static readonly string CertificateProfileName = \"testProfile\";\n\n        private readonly Mock<CertificateProfileClient> _client = new();\n        private readonly Mock<RSA> _rsaPublicKey = new();\n\n        [Fact]\n        public void Constructor_WhenClientIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new RSAArtifactSigning(client: null!, AccountName, CertificateProfileName, _rsaPublicKey.Object));\n\n            Assert.Equal(\"client\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenAccountNameIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new RSAArtifactSigning(_client.Object, accountName: null!, CertificateProfileName, _rsaPublicKey.Object));\n\n            Assert.Equal(\"accountName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenAccountNameIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new RSAArtifactSigning(_client.Object, accountName: string.Empty, CertificateProfileName, _rsaPublicKey.Object));\n\n            Assert.Equal(\"accountName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProfileNameIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new RSAArtifactSigning(_client.Object, AccountName, certificateProfileName: null!, _rsaPublicKey.Object));\n\n            Assert.Equal(\"certificateProfileName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProfileNameIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new RSAArtifactSigning(_client.Object, AccountName, certificateProfileName: string.Empty, _rsaPublicKey.Object));\n\n            Assert.Equal(\"certificateProfileName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Dispose_DisposesRSAKeyVaultAndRSAPublicKey()\n        {\n            RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n            rsa.Dispose();\n\n            _rsaPublicKey.Protected().Verify(nameof(RSA.Dispose), Times.Once(), [true]);\n        }\n\n        [Fact]\n        public void ExportParameters_IncludePrivateParametersIsTrue_Throws()\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            Assert.Throws<NotSupportedException>(\n                () => rsa.ExportParameters(true));\n        }\n\n        [Fact]\n        public void ExportParameters_IncludePrivateParametersIsFalse_UsesExportParametersOfPublicKey()\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            rsa.ExportParameters(false);\n\n            _rsaPublicKey.Verify(_ => _.ExportParameters(false), Times.Once());\n        }\n\n        [Fact]\n        public void ImportParameters_Throws()\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            Assert.Throws<NotImplementedException>(\n                () => rsa.ImportParameters(default));\n        }\n\n        [Fact]\n        public void SignHash_InvalidHashLength_Throws()\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            byte[] hash = [];\n            HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;\n            RSASignaturePadding padding = RSASignaturePadding.Pkcs1;\n\n            Assert.Throws<NotSupportedException>(\n                () => rsa.SignHash(hash, hashAlgorithmName, padding));\n        }\n\n        [Theory]\n        [InlineData(32, nameof(RSASignaturePadding.Pkcs1), nameof(SignatureAlgorithm.RS256))]\n        [InlineData(32, nameof(RSASignaturePadding.Pss), nameof(SignatureAlgorithm.PS256))]\n        [InlineData(48, nameof(RSASignaturePadding.Pkcs1), nameof(SignatureAlgorithm.RS384))]\n        [InlineData(48, nameof(RSASignaturePadding.Pss), nameof(SignatureAlgorithm.PS384))]\n        [InlineData(64, nameof(RSASignaturePadding.Pkcs1), nameof(SignatureAlgorithm.RS512))]\n        [InlineData(64, nameof(RSASignaturePadding.Pss), nameof(SignatureAlgorithm.PS512))]\n        public void SignHash_UsesClient(int hashLength, string paddingName, string expectedSignatureAlgorithmName)\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            RSASignaturePadding padding = paddingName switch\n            {\n                nameof(RSASignaturePadding.Pkcs1) => RSASignaturePadding.Pkcs1,\n                nameof(RSASignaturePadding.Pss) => RSASignaturePadding.Pss,\n                _ => throw new InvalidOperationException($\"Unknown padding name: {paddingName}\"),\n            };\n\n            SignatureAlgorithm expectedSignatureAlgorithm = expectedSignatureAlgorithmName switch\n            {\n                nameof(SignatureAlgorithm.RS256) => SignatureAlgorithm.RS256,\n                nameof(SignatureAlgorithm.PS256) => SignatureAlgorithm.PS256,\n                nameof(SignatureAlgorithm.RS384) => SignatureAlgorithm.RS384,\n                nameof(SignatureAlgorithm.PS384) => SignatureAlgorithm.PS384,\n                nameof(SignatureAlgorithm.RS512) => SignatureAlgorithm.RS512,\n                nameof(SignatureAlgorithm.PS512) => SignatureAlgorithm.PS512,\n                _ => throw new InvalidOperationException($\"Unknown signature algorithm name: {expectedSignatureAlgorithmName}\"),\n            };\n\n            byte[] signature = [];\n            byte[] hash = new byte[hashLength];\n            HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;\n            Mock<Response<SignStatus>> response = new();\n            Mock<CertificateProfileSignOperation> operation = new();\n\n            response\n                .SetupGet(_ => _.Value)\n                    .Returns(new SignStatus(Guid.NewGuid(), Status.Succeeded, signature, []));\n\n            operation\n                .Setup(_ => _.WaitForCompletion(default))\n                .Returns(response.Object);\n\n            _client.Setup(_ => _.StartSign(AccountName, CertificateProfileName, It.IsAny<SignRequest>(), null, null, null, default))\n                    .Returns(operation.Object);\n\n            var result = rsa.SignHash(hash, hashAlgorithmName, padding);\n\n            Assert.Same(signature, result);\n\n            _client.Verify(_ => _.StartSign(\n                AccountName,\n                CertificateProfileName,\n                It.Is<SignRequest>(request => request.SignatureAlgorithm == expectedSignatureAlgorithm && ReferenceEquals(request.Digest, hash)),\n                null,\n                null,\n                null,\n                default), Times.Once());\n        }\n\n        [Fact]\n        public void VerifyHash_UsesPublicKey()\n        {\n            using RSAArtifactSigning rsa = new(_client.Object, AccountName, CertificateProfileName, _rsaPublicKey.Object);\n\n            byte[] hash = [];\n            byte[] signature = [];\n            HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;\n            RSASignaturePadding padding = RSASignaturePadding.Pkcs1;\n\n            rsa.VerifyHash(hash, signature, hashAlgorithmName, padding);\n\n            _rsaPublicKey.Verify(_ => _.VerifyHash(hash, signature, hashAlgorithmName, padding), Times.Once());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.ArtifactSigning.Test/Sign.SignatureProviders.ArtifactSigning.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Moq\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.SignatureProviders.ArtifactSigning\\Sign.SignatureProviders.ArtifactSigning.csproj\" />\n    <ProjectReference Include=\"..\\Sign.TestInfrastructure\\Sign.TestInfrastructure.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Sign.SignatureProviders.ArtifactSigning.Test/TrustedSigningServiceProviderTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Azure.CodeSigning;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.SignatureProviders.ArtifactSigning.Test\n{\n    public class ArtifactSigningServiceProviderTests\n    {\n        private readonly ArtifactSigningServiceProvider _provider = new();\n        private readonly IServiceProvider serviceProvider;\n\n        public ArtifactSigningServiceProviderTests()\n        {\n            ServiceCollection services = new();\n            services.AddSingleton<ILogger<ArtifactSigningService>>(new TestLogger<ArtifactSigningService>());\n            services.AddSingleton<ArtifactSigningService>(sp =>\n            {\n                return new ArtifactSigningService(\n                     Mock.Of<CertificateProfileClient>(),\n                     \"account\",\n                     \"profile\",\n                     sp.GetRequiredService<ILogger<ArtifactSigningService>>());\n            });\n            serviceProvider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.GetSignatureAlgorithmProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_WhenServiceProviderIsValid_ReturnsInstance()\n        {\n            Assert.IsType<ArtifactSigningService>(_provider.GetSignatureAlgorithmProvider(serviceProvider));\n        }\n\n        [Fact]\n        public void GetCertificateProvider_WhenServiceProviderIsValid_ReturnsInstance()\n        {\n            Assert.IsType<ArtifactSigningService>(_provider.GetCertificateProvider(serviceProvider));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.ArtifactSigning.Test/TrustedSigningServiceTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Azure.CodeSigning;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.SignatureProviders.ArtifactSigning;\n\nnamespace Sign.SignatureProviders.TrustedSigning.Test\n{\n    public class TrustedSigningServiceTests\n    {\n        private static readonly CertificateProfileClient CertificateProfileClient = Mock.Of<CertificateProfileClient>();\n        private const string AccountName = \"a\";\n        private const string CertificateProfileName = \"b\";\n        private static readonly ILogger<ArtifactSigningService> Logger = Mock.Of<ILogger<ArtifactSigningService>>();\n\n        [Fact]\n        public void Constructor_WhenCertificateProfileClientIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningService(certificateProfileClient: null!, AccountName, CertificateProfileName, Logger));\n\n            Assert.Equal(\"certificateProfileClient\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenAccountNameIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningService(CertificateProfileClient, accountName: null!, CertificateProfileName, Logger));\n\n            Assert.Equal(\"accountName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenAccountNameIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new ArtifactSigningService(CertificateProfileClient, accountName: string.Empty, CertificateProfileName, Logger));\n\n            Assert.Equal(\"accountName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProfileNameIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningService(CertificateProfileClient, AccountName, certificateProfileName: null!, Logger));\n\n            Assert.Equal(\"certificateProfileName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateProfileNameIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new ArtifactSigningService(CertificateProfileClient, AccountName, certificateProfileName: string.Empty, Logger));\n\n            Assert.Equal(\"certificateProfileName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new ArtifactSigningService(CertificateProfileClient, AccountName, CertificateProfileName, logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.ArtifactSigning.Test/Usings.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nglobal using Xunit;"
  },
  {
    "path": "test/Sign.SignatureProviders.CertificateStore.Test/CertificateStoreServiceProviderTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing System.Security.Cryptography;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.Core;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.SignatureProviders.CertificateStore.Test\n{\n    public class CertificateStoreServiceProviderTests\n    {\n        private const string CertificateFingerprint = \"a\";\n        private static readonly HashAlgorithmName CertificateFingerprintAlgorithm = HashAlgorithmName.SHA256;\n        private const string? CryptoServiceProvider = \"b\";\n        private const string? PrivateKeyContainer = \"c\";\n        private const string? CertificateFilePath = null;\n        private const string? CertificateFilePassword = null;\n        private const bool IsMachineKeyContainer = true;\n        private const bool IsInteractive = false;\n        private readonly IServiceProvider serviceProvider;\n\n        public CertificateStoreServiceProviderTests()\n        {\n            ServiceCollection services = new();\n            services.AddSingleton<ILogger<CertificateStoreService>>(new TestLogger<CertificateStoreService>());\n            serviceProvider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateFingerprintIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreServiceProvider(certificateFingerprint: null!, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"certificateFingerprint\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateFingerprintIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new CertificateStoreServiceProvider(certificateFingerprint: string.Empty, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"certificateFingerprint\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCryptoServiceProviderIsNullAndPrivateKeyContainerIsNot_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreServiceProvider(CertificateFingerprint, CertificateFingerprintAlgorithm, cryptoServiceProvider: null, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"cryptoServiceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCryptoServiceProviderIsEmptyAndPrivateKeyContainerIsNot_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new CertificateStoreServiceProvider(CertificateFingerprint, CertificateFingerprintAlgorithm, cryptoServiceProvider: string.Empty, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"cryptoServiceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenPrivateKeyContainerIsNullAndCryptoServiceProviderIsNot_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreServiceProvider(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, privateKeyContainer: null, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"privateKeyContainer\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenPrivateKeyContainerIsEmptyAndCryptoServiceProviderIsNot_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new CertificateStoreServiceProvider(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, privateKeyContainer: string.Empty, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"privateKeyContainer\", exception.ParamName);\n        }\n\n        [Theory]\n        [InlineData(null, null)]\n        [InlineData(null, \"\")]\n        [InlineData(\"\", null)]\n        [InlineData(\"\", \"\")]\n        public void Constructor_WhenPrivateKeyContainerAndCryptoServiceProviderAreBothNullOrEmpty_DoesNotThrow(string? cryptoServiceProvider, string? privateKeyContainer)\n        {\n            CertificateStoreServiceProvider provider = new(CertificateFingerprint, CertificateFingerprintAlgorithm, cryptoServiceProvider, privateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive);\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_WhenServiceProviderIsNull_Throws()\n        {\n            CertificateStoreServiceProvider provider = new(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive);\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => provider.GetSignatureAlgorithmProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_ReturnsSameInstance()\n        {\n            CertificateStoreServiceProvider provider = new(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive);\n\n            ConcurrentBag<ISignatureAlgorithmProvider> signatureAlgorithmProviders = [];\n            Parallel.For(0, 2, (_, _) =>\n            {\n                signatureAlgorithmProviders.Add(provider.GetSignatureAlgorithmProvider(serviceProvider));\n            });\n\n            Assert.Equal(2, signatureAlgorithmProviders.Count);\n            Assert.Same(signatureAlgorithmProviders.First(), signatureAlgorithmProviders.Last());\n        }\n\n        [Fact]\n        public void GetCertificateProvider_WhenServiceProviderIsNull_Throws()\n        {\n            CertificateStoreServiceProvider provider = new(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive);\n\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => provider.GetCertificateProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetCertificateProvider_ReturnsSameInstance()\n        {\n            CertificateStoreServiceProvider provider = new(CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive);\n\n            ConcurrentBag<ICertificateProvider> certificateProviders = [];\n            Parallel.For(0, 2, (_, _) =>\n            {\n                certificateProviders.Add(provider.GetCertificateProvider(serviceProvider));\n            });\n\n            Assert.Equal(2, certificateProviders.Count);\n            Assert.Same(certificateProviders.First(), certificateProviders.Last());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.CertificateStore.Test/CertificateStoreServiceTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.SignatureProviders.CertificateStore.Test\n{\n    public class CertificateStoreServiceTests\n    {\n        private const string CertificateFingerprint = \"a\";\n        private static readonly HashAlgorithmName CertificateFingerprintAlgorithm = HashAlgorithmName.SHA256;\n        private const string? CryptoServiceProvider = \"b\";\n        private const string? PrivateKeyContainer = \"c\";\n        private const string? CertificateFilePath = null;\n        private const string? CertificateFilePassword = null;\n        private const bool IsMachineKeyContainer = true;\n        private const bool IsInteractive = false;\n        private readonly IServiceProvider serviceProvider;\n\n        public CertificateStoreServiceTests()\n        {\n            ServiceCollection services = new();\n            services.AddSingleton<ILogger<CertificateStoreService>>(new TestLogger<CertificateStoreService>());\n            serviceProvider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void Constructor_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreService(serviceProvider: null!, CertificateFingerprint, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateFingerprintIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new CertificateStoreService(serviceProvider, certificateFingerprint: null!, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"certificateFingerprint\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateFingerprintIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new CertificateStoreService(serviceProvider, certificateFingerprint: string.Empty, CertificateFingerprintAlgorithm, CryptoServiceProvider, PrivateKeyContainer, CertificateFilePath, CertificateFilePassword, IsMachineKeyContainer, IsInteractive));\n\n            Assert.Equal(\"certificateFingerprint\", exception.ParamName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.CertificateStore.Test/Sign.SignatureProviders.CertificateStore.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.SignatureProviders.CertificateStore\\Sign.SignatureProviders.CertificateStore.csproj\" />\n    <ProjectReference Include=\"..\\Sign.TestInfrastructure\\Sign.TestInfrastructure.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Sign.SignatureProviders.CertificateStore.Test/Usings.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nglobal using Xunit;"
  },
  {
    "path": "test/Sign.SignatureProviders.KeyVault.Test/KeyVaultServiceProviderTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Azure.Security.KeyVault.Certificates;\nusing Azure.Security.KeyVault.Keys.Cryptography;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.SignatureProviders.KeyVault.Test\n{\n    public class KeyVaultServiceProviderTests\n    {\n        private readonly KeyVaultServiceProvider _provider = new();\n        private readonly IServiceProvider serviceProvider;\n\n        public KeyVaultServiceProviderTests()\n        {\n            ServiceCollection services = new();\n            services.AddSingleton<ILogger<KeyVaultService>>(new TestLogger<KeyVaultService>());\n            services.AddSingleton<KeyVaultService>(sp =>\n            {\n                return new KeyVaultService(\n                    Mock.Of<CertificateClient>(),\n                    Mock.Of<CryptographyClient>(),\n                    \"a\", sp.GetRequiredService<ILogger<KeyVaultService>>());\n            });\n            serviceProvider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.GetSignatureAlgorithmProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetSignatureAlgorithmProvider_WhenServiceProviderIsValid_ReturnsSameInstance()\n        {\n            KeyVaultServiceProvider provider = new();\n\n            Assert.IsType<KeyVaultService>(_provider.GetSignatureAlgorithmProvider(serviceProvider));\n        }\n\n        [Fact]\n        public void GetCertificateProvider_WhenServiceProviderIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => _provider.GetCertificateProvider(serviceProvider: null!));\n\n            Assert.Equal(\"serviceProvider\", exception.ParamName);\n        }\n\n        [Fact]\n        public void GetCertificateProvider_WhenServiceProviderIsValid_ReturnsSameInstance()\n        {\n            Assert.IsType<KeyVaultService>(_provider.GetCertificateProvider(serviceProvider));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.KeyVault.Test/KeyVaultServiceTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\nusing Azure;\nusing Azure.Security.KeyVault.Certificates;\nusing Azure.Security.KeyVault.Keys.Cryptography;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing Sign.TestInfrastructure;\n\nnamespace Sign.SignatureProviders.KeyVault.Test\n{\n    public class KeyVaultServiceTests\n    {\n        private const string CertificateName = \"a\";\n        private static readonly ILogger<KeyVaultService> Logger = Mock.Of<ILogger<KeyVaultService>>();\n\n        private readonly Mock<CertificateClient> _certificateClient = new();\n        private readonly Mock<CryptographyClient> _cryptographyClient = new();\n\n        [Fact]\n        public void Constructor_WhenCertificateClientIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new KeyVaultService(certificateClient: null!, _cryptographyClient.Object, CertificateName, Logger));\n\n            Assert.Equal(\"certificateClient\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCryptographyClientIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new KeyVaultService(_certificateClient.Object, cryptographyClient: null!, CertificateName, Logger));\n\n            Assert.Equal(\"cryptographyClient\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateNameIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new KeyVaultService(_certificateClient.Object, _cryptographyClient.Object, certificateName: null!, Logger));\n\n            Assert.Equal(\"certificateName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateNameIsEmpty_Throws()\n        {\n            ArgumentException exception = Assert.Throws<ArgumentException>(\n                () => new KeyVaultService(_certificateClient.Object, _cryptographyClient.Object, certificateName: string.Empty, Logger));\n\n            Assert.Equal(\"certificateName\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenLoggerIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new KeyVaultService(_certificateClient.Object, _cryptographyClient.Object, CertificateName, logger: null!));\n\n            Assert.Equal(\"logger\", exception.ParamName);\n        }\n\n        [Fact]\n        public async Task GetCertificateAsync_CalledTwice_CertificateRetrievedOnce()\n        {\n            CancellationToken cancellationToken = CancellationToken.None;\n            Mock<KeyVaultCertificateWithPolicy> certificate = CreateMockKeyVaultCertificateWithPolicy();\n            Mock<Response<KeyVaultCertificateWithPolicy>> response = new();\n\n            response\n                .Setup(_ => _.Value)\n                .Returns(certificate.Object);\n\n            _certificateClient\n                .Setup(_ => _.GetCertificateAsync(CertificateName, cancellationToken))\n                .ReturnsAsync(response.Object);\n\n            using KeyVaultService service = new(_certificateClient.Object, _cryptographyClient.Object, CertificateName, Logger);\n\n            using X509Certificate2 certificate1 = await service.GetCertificateAsync(cancellationToken);\n            using X509Certificate2 certificate2 = await service.GetCertificateAsync(cancellationToken);\n\n            _certificateClient.Verify(_ => _.GetCertificateAsync(CertificateName, cancellationToken), Times.Once);\n        }\n\n        [Fact]\n        public async Task GetRsaAsync_ReturnsRSAKeyVaultWrapper()\n        {\n            CancellationToken cancellationToken = CancellationToken.None;\n            Mock<KeyVaultCertificateWithPolicy> certificate = CreateMockKeyVaultCertificateWithPolicy();\n            Mock<RSAKeyVault> rsaKeyVault = new(Mock.Of<CryptographyClient>(), \"testId\", null);\n            Mock<Response<KeyVaultCertificateWithPolicy>> response = new();\n\n            response\n                .Setup(_ => _.Value)\n                .Returns(certificate.Object);\n\n            _certificateClient\n                .Setup(_ => _.GetCertificateAsync(CertificateName, cancellationToken))\n                .ReturnsAsync(response.Object);\n\n            _cryptographyClient\n                .Setup(_ => _.CreateRSAAsync(cancellationToken))\n                .ReturnsAsync(rsaKeyVault.Object);\n\n            using KeyVaultService service = new(_certificateClient.Object, _cryptographyClient.Object, CertificateName, Logger);\n\n            using RSA rsa = await service.GetRsaAsync(cancellationToken);\n\n            Assert.IsType<RSAKeyVaultWrapper>(rsa);\n        }\n\n        private static Mock<KeyVaultCertificateWithPolicy> CreateMockKeyVaultCertificateWithPolicy()\n        {\n            CertificateProperties certificateProperties = new(\"test\");\n            byte[] publicKey = SelfIssuedCertificateCreator.CreateCertificate().Export(X509ContentType.Cert);\n            Mock<KeyVaultCertificateWithPolicy> certificate = new(certificateProperties);\n\n            // We need to do this because the property has an internal setter\n            typeof(KeyVaultCertificateWithPolicy)\n                .GetProperty(nameof(KeyVaultCertificateWithPolicy.Cer))\n                ?.GetSetMethod(nonPublic: true)\n                ?.Invoke(certificate.Object, [publicKey]);\n\n            return certificate;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.KeyVault.Test/RSAKeyVaultWrapperTests.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing Azure.Security.KeyVault.Keys.Cryptography;\nusing Moq;\nusing Moq.Protected;\n\nnamespace Sign.SignatureProviders.KeyVault.Test\n{\n    public class RSAKeyVaultWrapperTests\n    {\n        private readonly Mock<RSAKeyVault> _rsaKeyVault = new(Mock.Of<CryptographyClient>(), \"testId\", null);\n        private readonly Mock<RSA> _rsaPublicKey = new();\n\n        [Fact]\n        public void Constructor_WhenRSAKeyVaultIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new RSAKeyVaultWrapper(rsaKeyVault: null!, _rsaPublicKey.Object));\n\n            Assert.Equal(\"rsaKeyVault\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Constructor_WhenCertificateClientIsNull_Throws()\n        {\n            ArgumentNullException exception = Assert.Throws<ArgumentNullException>(\n                () => new RSAKeyVaultWrapper(_rsaKeyVault.Object, rsaPublicKey: null!));\n\n            Assert.Equal(\"rsaPublicKey\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Dispose_DisposesRSAKeyVaultAndRSAPublicKey()\n        {\n            RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n            wrapper.Dispose();\n\n            _rsaKeyVault.Protected().Verify(nameof(RSAKeyVault.Dispose), Times.Once(), [true]);\n            _rsaPublicKey.Protected().Verify(nameof(RSA.Dispose), Times.Once(), [true]);\n        }\n\n        [Fact]\n        public void ExportParameters_IncludePrivateParametersIsTrue_Throws()\n        {\n            using RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n\n            Assert.Throws<NotSupportedException>(\n                () => wrapper.ExportParameters(true));\n        }\n\n        [Fact]\n        public void ExportParameters_IncludePrivateParametersIsFalse_UsesExportParametersOfPublicKey()\n        {\n            using RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n\n            wrapper.ExportParameters(false);\n\n            _rsaPublicKey.Verify(_ => _.ExportParameters(false), Times.Once());\n        }\n\n        [Fact]\n        public void ImportParameters_Throws()\n        {\n            using RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n\n            Assert.Throws<NotImplementedException>(\n                () => wrapper.ImportParameters(default));\n        }\n\n        [Fact]\n        public void SignHash_UsesRSAKeyVault()\n        {\n            using RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n\n            byte[] hash = [];\n            HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;\n            RSASignaturePadding padding = RSASignaturePadding.Pkcs1;\n\n            wrapper.SignHash(hash, hashAlgorithmName, padding);\n\n            _rsaKeyVault.Verify(_ => _.SignHash(hash, hashAlgorithmName, padding), Times.Once());\n        }\n\n        [Fact]\n        public void VerifyHash_UsesPublicKey()\n        {\n            using RSAKeyVaultWrapper wrapper = new(_rsaKeyVault.Object, _rsaPublicKey.Object);\n\n            byte[] hash = [];\n            byte[] signature = [];\n            HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;\n            RSASignaturePadding padding = RSASignaturePadding.Pkcs1;\n\n            wrapper.VerifyHash(hash, signature, hashAlgorithmName, padding);\n\n            _rsaPublicKey.Verify(_ => _.VerifyHash(hash, signature, hashAlgorithmName, padding), Times.Once());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.SignatureProviders.KeyVault.Test/Sign.SignatureProviders.KeyVault.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Moq\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.SignatureProviders.KeyVault\\Sign.SignatureProviders.KeyVault.csproj\" />\n    <ProjectReference Include=\"..\\Sign.TestInfrastructure\\Sign.TestInfrastructure.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Sign.SignatureProviders.KeyVault.Test/Usings.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nglobal using Xunit;"
  },
  {
    "path": "test/Sign.TestInfrastructure/Constants.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.TestInfrastructure\n{\n    public static class Constants\n    {\n        public const string CommonNamePrefix = \"Sign CLI Test\";\n        // This random GUID gives us a simple and robust way of identifying certificates created and trusted by these tests.\n        public const string FriendlyName = \"25d8c5cb-ee59-488e-a505-7ba664c255f2\";\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/EphemeralTrust.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Runtime.Versioning;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class EphemeralTrust : IDisposable\n    {\n        private readonly X509Certificate2 _certificate;\n\n        [SupportedOSPlatform(\"windows\")]\n        internal EphemeralTrust(X509Certificate2 certificate)\n        {\n            ArgumentNullException.ThrowIfNull(certificate, nameof(certificate));\n\n            // Note: This class does not assume ownership of the certificate.\n            _certificate = certificate;\n\n            AddTrust();\n        }\n\n        public void Dispose()\n        {\n            RemoveTrust();\n\n            // Do not dispose of _certificate, as this class did not assume ownership of it.\n        }\n\n        // If test certificates from a previous test run are still trusted,\n        // we need to remove them if we can or have them removed by the developer before continuing.\n        public static void RemoveResidualTestCertificates()\n        {\n            using (X509Store store = GetStore())\n            {\n                store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);\n\n                X509Certificate2Collection certificates = store.Certificates;\n                List<X509Certificate2> oldCertificates = new();\n\n                foreach (X509Certificate2 certificate in certificates)\n                {\n                    if (string.Equals(certificate.FriendlyName, Constants.FriendlyName))\n                    {\n                        oldCertificates.Add(certificate);\n                    }\n                }\n\n                store.Close();\n\n                if (oldCertificates.Count > 0)\n                {\n                    if (Environment.IsPrivilegedProcess)\n                    {\n                        store.Open(OpenFlags.ReadWrite | OpenFlags.OpenExistingOnly);\n\n                        try\n                        {\n                            foreach (X509Certificate2 certificate in oldCertificates)\n                            {\n                                store.Remove(certificate);\n                            }\n                        }\n                        finally\n                        {\n                            store.Close();\n                        }\n                    }\n                    else\n                    {\n                        StringBuilder messageBuilder = new();\n                        bool isSingular = oldCertificates.Count == 1;\n\n                        messageBuilder.Append($\"{oldCertificates.Count} certificate{(isSingular ? string.Empty : \"s\")} from a previous test run {(isSingular ? \"was\" : \"were\")} found \");\n                        messageBuilder.Append(\"in the local machine's \\\"Trusted Root Certification Authorities\\\" store.  \");\n                        messageBuilder.Append($\"Please remove the following certificate{(isSingular ? string.Empty : \"s\")} manually and rerun.  \");\n                        messageBuilder.Append($\"All test certificates have a \\\"Friendly Name\\\" value of {Constants.FriendlyName}.\");\n                        messageBuilder.AppendLine();\n\n                        foreach (X509Certificate2 certificate in oldCertificates)\n                        {\n                            messageBuilder.AppendLine($\"  Subject:  {certificate.Subject}\");\n                            messageBuilder.AppendLine($\"    Friendly name:  {certificate.FriendlyName}\");\n                        }\n\n                        throw new ResidualTestCertificatesFoundInRootStoreException(messageBuilder.ToString());\n                    }\n                }\n            }\n        }\n\n        [SupportedOSPlatform(\"windows\")]\n        private void AddTrust()\n        {\n            // This enables us to easily and reliably identify our test certificates.\n            _certificate.FriendlyName = Constants.FriendlyName;\n\n            using (X509Store store = GetStore())\n            {\n                store.Open(OpenFlags.ReadWrite | OpenFlags.OpenExistingOnly);\n\n                // CodeQL [SM02730] This is test code. This adds a short-lived test certificate to the root store for testing signing and signature verification. The certificate is later removed. See internal bug 2292291.\n                store.Add(_certificate);\n\n                store.Close();\n            }\n        }\n\n        private void RemoveTrust()\n        {\n            using (X509Store store = GetStore())\n            {\n                store.Open(OpenFlags.ReadWrite | OpenFlags.OpenExistingOnly);\n\n                store.Remove(_certificate);\n\n                store.Close();\n            }\n        }\n\n        private static X509Store GetStore()\n        {\n            // StoreName.Root is necessary for trust.\n            // StoreLocation.LocalMachine does not pop UI confirmation like StoreLocation.CurrentUser does.\n            return new X509Store(StoreName.Root, StoreLocation.LocalMachine);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/RequiresElevationTheoryAttribute.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Xunit;\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class RequiresElevationTheoryAttribute : TheoryAttribute\n    {\n        private const string SkipReason = \"Test skipped because it requires elevation.\";\n\n        private static readonly Lazy<bool> LazyShouldRun = new(ShouldRun);\n\n        public override string Skip\n        {\n            get { return LazyShouldRun.Value ? null! : SkipReason; }\n            set { base.Skip = value; }\n        }\n\n        private static bool ShouldRun()\n        {\n            // It is assumed that CI runs elevated by default,\n            // while dev machines don't.\n            return IsCI() || IsElevated();\n        }\n\n        private static bool IsCI()\n        {\n            string? value = Environment.GetEnvironmentVariable(\"CI\");\n\n            if (bool.TryParse(value, out bool boolValue))\n            {\n                return boolValue;\n            }\n\n            return false;\n        }\n\n        private static bool IsElevated()\n        {\n            return Environment.IsPrivilegedProcess;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/ResidualTestCertificatesFoundInRootStoreException.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class ResidualTestCertificatesFoundInRootStoreException : Exception\n    {\n        public ResidualTestCertificatesFoundInRootStoreException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/SelfIssuedCertificateCreator.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Security.Cryptography;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Sign.TestInfrastructure\n{\n    public static class SelfIssuedCertificateCreator\n    {\n        public static X509Certificate2 CreateCertificate()\n        {\n            DateTimeOffset now = DateTimeOffset.Now;\n\n            return CreateCertificate(now.AddMinutes(-5), now.AddMinutes(5));\n        }\n\n        public static X509Certificate2 CreateCertificate(DateTimeOffset notBefore, DateTimeOffset notAfter)\n        {\n            using (RSA keyPair = RSA.Create(keySizeInBits: 3072))\n            {\n                CertificateRequest request = new(\n                    $\"CN={Constants.CommonNamePrefix} Certificate ({Guid.NewGuid():D}), O=Organization, L=City, S=State, C=Country\",\n                    keyPair,\n                    HashAlgorithmName.SHA256,\n                    // CodeQL [SM03799] PKCS #1 v1.5 is required for interoperability with existing signature verifiers.\n                    RSASignaturePadding.Pkcs1);\n\n                return request.CreateSelfSigned(notBefore, notAfter);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/Sign.TestInfrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Import Project=\"$(RepositoryRootDirectory)\\SdkTools.props\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsUnitTestProject>true</IsUnitTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Moq\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Sign.Core\\Sign.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Sign.Core.Test\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Sign.TestInfrastructure/TemporaryFile.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class TemporaryFile : IDisposable\n    {\n        public FileInfo File { get; }\n\n        public TemporaryFile()\n        {\n            File = new(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n        }\n\n        public void Dispose()\n        {\n            File.Refresh();\n\n            if (File.Exists)\n            {\n                File.Delete();\n\n                File.Refresh();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/TestAssets.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Reflection;\n\nnamespace Sign.TestInfrastructure\n{\n    public static class TestAssets\n    {\n        public static FileInfo GetTestAsset(DirectoryInfo destinationDirectory, params string[] fileParts)\n        {\n            FileInfo thisAssemblyFile = new(Path.Combine(Assembly.GetExecutingAssembly().Location));\n            string sourceFilePath = Path.Combine([thisAssemblyFile.DirectoryName!, \"TestAssets\", .. fileParts]);\n            FileInfo sourceFile = new(sourceFilePath);\n            string destinationFilePath = Path.Combine([destinationDirectory.FullName, .. fileParts]);\n            FileInfo destinationFile = new(destinationFilePath);\n\n            destinationFile.Directory!.Create();\n\n            File.Copy(sourceFile.FullName, destinationFile.FullName);\n\n            return destinationFile;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/TestFileCreator.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.IO.Compression;\nusing Sign.Core;\n\nnamespace Sign.TestInfrastructure\n{\n    public static class TestFileCreator\n    {\n        internal static FileInfo CreateEmptyZipFile(TemporaryDirectory temporaryDirectory, string fileExtension)\n        {\n            FileInfo file = new(Path.Combine(temporaryDirectory.Directory.FullName, $\"{Path.GetRandomFileName()}{fileExtension}\"));\n\n            using (FileStream stream = file.OpenWrite())\n            using (ZipArchive zip = new(stream, ZipArchiveMode.Create))\n            {\n            }\n\n            return file;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Sign.TestInfrastructure/TestLogEntry.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class TestLogEntry\n    {\n        public LogLevel LogLevel { get; }\n        public string Message { get; }\n\n        internal TestLogEntry(LogLevel logLevel, string message)\n        {\n            LogLevel = logLevel;\n            Message = message;\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.TestInfrastructure/TestLogger.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sign.TestInfrastructure\n{\n    public sealed class TestLogger<T> : ILogger<T>\n    {\n        private readonly ConcurrentQueue<TestLogEntry> _entries = new();\n\n        public IEnumerable<TestLogEntry> Entries\n        {\n            get => _entries;\n        }\n\n        public IDisposable? BeginScope<TState>(TState state) where TState : notnull\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool IsEnabled(LogLevel logLevel)\n        {\n            return true;\n        }\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)\n        {\n            string message = formatter(state, exception);\n            TestLogEntry entry = new(logLevel, message);\n\n            _entries.Enqueue(entry);\n        }\n    }\n}"
  },
  {
    "path": "test/Sign.TestInfrastructure/TrustedCertificateFixture.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE.txt file in the project root for more information.\n\nusing System.Runtime.Versioning;\nusing System.Security.Cryptography.X509Certificates;\nusing Xunit;\n\nnamespace Sign.TestInfrastructure\n{\n    [CollectionDefinition(Name, DisableParallelization = true)]\n    public sealed class TrustedCertificateFixture : IDisposable\n    {\n        private const string Name = nameof(TrustedCertificateFixture);\n\n        private readonly EphemeralTrust? _ephemeralTrust;\n        private readonly X509Certificate2? _certificate;\n\n        public X509Certificate2 TrustedCertificate\n        {\n            get\n            {\n                if (Environment.IsPrivilegedProcess)\n                {\n                    return _certificate!;\n                }\n\n                throw new UnauthorizedAccessException(\"This test requires elevation.\");\n            }\n        }\n\n        [SupportedOSPlatform(\"windows\")]\n        public TrustedCertificateFixture()\n        {\n            if (Environment.IsPrivilegedProcess)\n            {\n                _certificate = SelfIssuedCertificateCreator.CreateCertificate();\n                _ephemeralTrust = new EphemeralTrust(_certificate);\n            }\n        }\n\n        public void Dispose()\n        {\n            if (Environment.IsPrivilegedProcess)\n            {\n                _ephemeralTrust?.Dispose();\n                TrustedCertificate?.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "triage-policy.md",
    "content": "# Issue Triage Policy\n\nThis policy aims to ensure that issues are handled efficiently and transparently, keeping the project on track and maintaining a high level of community engagement.\n\nFor reporting security vulnerabilities, follow [this guidance](SECURITY.md).\n\n## Categorize Issues\n\n* **Bugs**:  issues that describe a malfunction or unintended behavior\n* **Feature Requests**:  suggestions for new features or enhancements\n* **Documentation**:  issues related to missing or unclear documentation\n* **Questions**:  general inquiries or requests for clarification\n\n## Prioritize Issues\n\n* **Priority 0 (P0)**:  cannot release without addressing\n* **Priority 1 (P1)**:  blocking core scenarios, regressions, or high-impact issues affecting many users\n* **Priority 2 (P2)**:  important but not blocking, such as feature requests with significant community interest\n* **Priority 3 (P3)**:  low-impact issues, minor bugs, or enhancements with limited scope\n\n## Label Issues\n\n* Use labels to indicate the type and priority of the issue (e.g.:  [bug](https://github.com/dotnet/sign/labels/bug), [feature-request](https://github.com/dotnet/sign/labels/feature-request), [Priority:1](https://github.com/dotnet/sign/labels/Priority%3A1), [Priority:2](https://github.com/dotnet/sign/labels/Priority%3A2)).\n* Additional labels can be used for specific areas of the project (e.g., CLI, documentation).\n\n## Review and Update\n\n* Conduct triage meetings (typically weekly, except in December) to review new issues and update the status of existing ones.\n* If more information is needed from the community, the issue will be labelled with [needs-more-info](https://github.com/dotnet/sign/labels/needs-more-info) and awaited.\n* If information is needed from the issue author and the author has not responded within 14 days, the issue will be closed but can be reactivated when information is available.\n\n## Triage Outcome\n\nA triaged issue should fall into one of these states:\n\n* a priority has been assigned and the issue is in the backlog\n* the issue is labeled with needs-more-info and is waiting on user response\n* the issue is closed (e.g.:  question immediately answered)\n"
  }
]