[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome:http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Don't use tabs for indentation.\n[*]\nindent_style = space\n# (Please don't specify an indent_size here; that has too many unintended consequences.)\n\n# Code files\n[*.{cs,csx,vb,vbx}]\nindent_size = 4\n\n# Xml project files\n[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}]\nindent_size = 2\n\n# Xml config files\n[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct}]\nindent_size = 2\n\n# YAML files\n[*.{yaml,yml}]\nindent_size = 2\n\n# JSON files\n[*.json]\nindent_size = 2\n\n# Dotnet code style settings:\n[*.{cs,vb}]\ntab_width = 4\n\n# Sort using and Import directives with System.* appearing first\ndotnet_sort_system_directives_first = true\n# Avoid \"this.\" and \"Me.\" if not necessary\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_event = false:suggestion\n\n# Use language keywords instead of framework type names for type references\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\n# Suggest more modern language features when available\ndotnet_style_object_initializer = true:suggestion\ndotnet_style_collection_initializer = true:suggestion\ndotnet_style_coalesce_expression = true:suggestion\ndotnet_style_null_propagation = true:suggestion\ndotnet_style_explicit_tuple_names = true:suggestion\n\n# CSharp code style settings:\n\n# IDE0040: Add accessibility modifiers\ndotnet_style_require_accessibility_modifiers = omit_if_default:error\n\n# IDE0040: Add accessibility modifiers\ndotnet_diagnostic.IDE0040.severity = error\n\n# IDE1100: Error reading content of source file 'Project.TargetFrameworkMoniker' (i.e. from ThisAssembly)\ndotnet_diagnostic.IDE1100.severity = none\n\n[*.cs]\n# Top-level files are definitely OK\ncsharp_using_directive_placement = outside_namespace:silent\ncsharp_style_namespace_declarations = block_scoped:silent\ncsharp_prefer_simple_using_statement = true:suggestion\ncsharp_prefer_braces = true:silent\n\n# Prefer \"var\" everywhere\ncsharp_style_var_for_built_in_types = true:suggestion\ncsharp_style_var_when_type_is_apparent = true:suggestion\ncsharp_style_var_elsewhere = true:suggestion\n\n# Prefer method-like constructs to have an expression-body\ncsharp_style_expression_bodied_methods = true:none\ncsharp_style_expression_bodied_constructors = true:none\ncsharp_style_expression_bodied_operators = true:none\n\n# Prefer property-like constructs to have an expression-body\ncsharp_style_expression_bodied_properties = true:none\ncsharp_style_expression_bodied_indexers = true:none\ncsharp_style_expression_bodied_accessors = true:none\n\n# Suggest more modern language features when available\ncsharp_style_pattern_matching_over_is_with_cast_check = true:error\ncsharp_style_pattern_matching_over_as_with_null_check = true:error\ncsharp_style_inlined_variable_declaration = true:suggestion\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_conditional_delegate_call = true:suggestion\n\n# Newline settings\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_before_else = true\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_members_in_anonymous_types = true\n\n# Test settings\n[**/*Tests*/**{.cs,.vb}]\n# xUnit1013: Public method should be marked as test. Allows using records as test classes\ndotnet_diagnostic.xUnit1013.severity = none\n\n# CS9113: Parameter is unread (usually, ITestOutputHelper)\ndotnet_diagnostic.CS9113.severity = none\n\n# Default severity for analyzer diagnostics with category 'Style'\ndotnet_analyzer_diagnostic.category-Style.severity = none\n\n# VSTHRD200: Use \"Async\" suffix for async methods\ndotnet_diagnostic.VSTHRD200.severity = none\n"
  },
  {
    "path": ".gitattributes",
    "content": "# normalize by default\n* text=auto encoding=UTF-8\n*.sh text eol=lf\n*.sbn eol=lf\n\n# These are windows specific files which we may as well ensure are\n# always crlf on checkout\n*.bat text eol=crlf\n*.cmd text eol=crlf\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: devlooped\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "contact_links:\n  - name: Questions\n    url: https://github.com/devlooped/SmallSharp/discussions?discussions_q=category%3AQ%26A\n    about: Want to know how to do something? Check out the Discussions > Q&A area!\n  - name: Ideas\n    url: https://github.com/devlooped/SmallSharp/discussions?discussions_q=category%3AIdeas\n    about: Suggest an idea to make the project better through the Discussions > Ideas area!\n"
  },
  {
    "path": ".github/actions/dotnet/action.yml",
    "content": "name: ⚙ dotnet\ndescription: Configures dotnet if the repo/org defines the DOTNET custom property\n\nruns:\n  using: composite\n  steps:\n    - name: 🔎 dotnet\n      id: dotnet\n      shell: bash\n      run: |\n        VERSIONS=$(gh api repos/${{ github.repository }}/properties/values | jq -r '.[] | select(.property_name == \"DOTNET\") | .value')\n        # Remove extra whitespace from VERSIONS\n        VERSIONS=$(echo \"$VERSIONS\" | tr -s ' ' | tr -d ' ')\n        # Convert comma-separated to newline-separated\n        NEWLINE_VERSIONS=$(echo \"$VERSIONS\" | tr ',' '\\n')\n        # Validate versions\n        while IFS= read -r version; do\n          if ! [[ $version =~ ^[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?(\\.x)?$ ]]; then\n            echo \"Error: Invalid version format: $version\"\n            exit 1\n          fi\n        done <<< \"$NEWLINE_VERSIONS\"\n        # Write multiline output to $GITHUB_OUTPUT\n        {\n          echo 'versions<<EOF'\n          echo \"$NEWLINE_VERSIONS\"\n          echo 'EOF'\n        } >> $GITHUB_OUTPUT\n\n    - name: ⚙ dotnet\n      if: steps.dotnet.outputs.versions != ''\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: |\n          ${{ steps.dotnet.outputs.versions }}\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "# .NET Repository\n\n**Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**\n\n## Working Effectively\n\n### Essential Build Commands\n- **Restore dependencies**: `dotnet restore`\n\n- **Build the entire solution**: `dotnet build`\n\n- **Run tests**: `dnx --yes retest`\n  - Runs all unit tests across the solution\n  - If tests fail due to Azure Storage, run the following commands and retry: `npm install azurite` and `npx azurite &`\n\n### Build Validation and CI Requirements\n- **Always run before committing**: \n  * `dnx --yes retest`\n  * `dotnet format whitespace -v:diag --exclude ~/.nuget`\n  * `dotnet format style -v:diag --exclude ~/.nuget`\n\n### Project Structure and Navigation\n\n| Directory | Description |\n|-----------|-------------|\n| `src/` | Contains the repo source code. |\n| `bin/` | Contains built packages (if any) |\n\n### Code Style and Formatting\n\n#### EditorConfig Rules\nThe repository uses `.editorconfig` at the repo root for consistent code style.\n\n- **Indentation**: 4 spaces for C# files, 2 spaces for XML/YAML/JSON\n- **Line endings**: LF (Unix-style)\n- **Sort using directives**: System.* namespaces first (`dotnet_sort_system_directives_first = true`)\n- **Type references**: Prefer language keywords over framework type names (`int` vs `Int32`)\n- **Modern C# features**: Use object/collection initializers, coalesce expressions when possible, use var when the type is apparent from the right-hand side of the assignment\n- **Visibility modifiers**: only explicitly specify visibility when different from the default (e.g. `public` for classes, no `internal` for classes or `private` for fields, etc.)\n\n#### Formatting Validation\n- CI enforces formatting with `dotnet format whitespace` and `dotnet format style`\n- Run locally: `dotnet format whitespace --verify-no-changes -v:diag --exclude ~/.nuget`\n- Fix formatting: `dotnet format` (without `--verify-no-changes`)\n\n### Testing Practices\n\n#### Test Framework\n- **xUnit** for all unit and integration tests\n- **Moq** for mocking dependencies\n- Located in `src/*.Tests/`\n\n#### Test Attributes\nCustom xUnit attributes are sometimes used for conditional test execution:\n- `[SecretsFact(\"XAI_API_KEY\")]` - Skips test if required secrets are missing from user secrets or environment variables\n- `[LocalFact(\"SECRET\")]` - Runs only locally (skips in CI), requires specified secrets\n- `[CIFact]` - Runs only in CI environment\n\n### Dependency Management\n\n#### Adding Dependencies\n- Add to appropriate `.csproj` file\n- Run `dotnet restore` to update dependencies\n- Ensure version consistency across projects where applicable\n\n#### CI/CD Pipeline\n- **Build workflow**: `.github/workflows/build.yml` - runs on PR and push to main/rel/feature branches\n- **Publish workflow**: Publishes to Sleet feed when `SLEET_CONNECTION` secret is available\n- **OS matrix**: Configured in `.github/workflows/os-matrix.json` (defaults to ubuntu-latest)\n\n### Special Files and Tools\n\n#### dnx Command\n- **Purpose**: built-in tool for running arbitrary dotnet tools that are published on nuget.org. `--yes` auto-confirms install before run.\n- **Example**: `dnx --yes retest` - runs tests with automatic retry on transient failures (retest being a tool package published at https://www.nuget.org/packages/retest)\n- **In CI**: `dnx --yes retest -- --no-build` (skips build, runs tests only)\n\n#### Directory.Build.rsp\n- MSBuild response file with default build arguments\n- `-nr:false` - disables node reuse\n- `-m:1` - single-threaded build (for stability)\n- `-v:m` - minimal verbosity\n\n#### Code Quality\n- All PRs must pass format validation\n- Tests must pass on all target frameworks\n- Follow existing patterns and conventions in the codebase\n\n## Documenting Work\n\nProject implemention details, design and key decisions should be documented in a top-level AGENTS.md file at the repo root. \nKeep this file updated whenever you make change significant changes for future reference.\n\nUser-facing features and APIs should be documented to highlight (not extensively, as an overview) key project features and capabilities, in the readme.md file at the repo root.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n- package-ecosystem: nuget\n  directory: /\n  schedule:\n    interval: daily\n  groups:\n    Azure:\n      patterns:\n        - \"Azure*\"\n        - \"Microsoft.Azure*\"\n    Identity:\n      patterns:\n        - \"System.IdentityModel*\"\n        - \"Microsoft.IdentityModel*\"\n    System:\n      patterns:\n        - \"System*\"\n      exclude-patterns:\n        - \"System.IdentityModel*\"\n    Extensions:\n      patterns:\n        - \"Microsoft.Extensions*\"\n      exclude-patterns:\n        - \"Microsoft.Extensions.AI*\"\n    ExtensionsAI:\n      patterns:\n        - \"Microsoft.Extensions.AI*\"\n    Web:\n      patterns:\n        - \"Microsoft.AspNetCore*\"\n    Tests:\n      patterns:\n        - \"Microsoft.NET.Test*\"\n        - \"xunit*\"\n        - \"coverlet*\"\n    ThisAssembly:\n      patterns:\n        - \"ThisAssembly*\"\n    ProtoBuf:\n      patterns:\n        - \"protobuf-*\"\n    Spectre:\n      patterns:\n        - \"Spectre.Console*\"\n"
  },
  {
    "path": ".github/dotnet.json",
    "content": "[\n  \"10.x\"\n]\n"
  },
  {
    "path": ".github/release.yml",
    "content": "changelog:\n  exclude:\n    labels:\n      - bydesign\n      - dependencies\n      - duplicate\n      - question\n      - invalid\n      - wontfix\n      - need info\n      - techdebt\n    authors:\n      - devlooped-bot\n      - dependabot\n      - github-actions\n  categories:\n    - title: ✨ Implemented enhancements\n      labels: \n        - enhancement\n    - title: 🐛 Fixed bugs\n      labels: \n        - bug        \n    - title: 📝 Documentation updates\n      labels: \n        - docs\n        - documentation\n    - title: 🔨 Other\n      labels: \n        - '*'\n      exclude:\n        labels:\n          - dependencies\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "﻿# Builds and runs tests in all three supported OSes\n# Pushes CI feed if secrets.SLEET_CONNECTION is provided\n\nname: build\non: \n  workflow_dispatch:\n    inputs:\n      configuration:\n        type: choice\n        description: Configuration\n        options: \n        - Release\n        - Debug\n  push:\n    branches: [ main, 'feature/*', 'rel/*' ]\n    paths-ignore:\n      - changelog.md\n      - readme.md\n  pull_request:\n    types: [opened, synchronize, reopened]\n\nenv:\n  DOTNET_NOLOGO: true\n  PackOnBuild: true\n  GeneratePackageOnBuild: true\n  VersionPrefix: 42.42.${{ github.run_number }}\n  VersionLabel: ${{ github.ref }}\n  GH_TOKEN: ${{ secrets.GH_TOKEN }}\n  MSBUILDTERMINALLOGGER: auto\n  Configuration: ${{ github.event.inputs.configuration || 'Release' }}\n  SLEET_FEED_URL: ${{ vars.SLEET_FEED_URL }}\n\ndefaults:\n  run:\n    shell: bash\n\njobs:\n  os-matrix:\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.lookup.outputs.matrix }}\n    steps:\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        \n      - name: 🔎 lookup\n        id: lookup\n        shell: pwsh\n        run: |\n          $path = './.github/workflows/os-matrix.json'\n          $os = if (test-path $path) { cat $path } else { '[\"ubuntu-latest\"]' }\n          echo \"matrix=$os\" >> $env:GITHUB_OUTPUT\n\n  build:\n    needs: os-matrix\n    name: build-${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: ${{ fromJSON(needs.os-matrix.outputs.matrix) }}\n    steps:\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with: \n          submodules: recursive\n          fetch-depth: 0\n\n      - name: ⚙ dotnet\n        uses: devlooped/actions-dotnet-env@v1\n\n      - name: 🙏 build\n        run: dotnet build -m:1 -bl:build.binlog\n\n      - name: 🧪 test\n        shell: pwsh\n        run: dnx --yes retest -- --no-build\n\n      - name: 🐛 logs\n        uses: actions/upload-artifact@v4\n        if: runner.debug && always()\n        with:\n          name: logs\n          path: '*.binlog'\n\n      - name: 🚀 sleet\n        env:\n          SLEET_CONNECTION: ${{ secrets.SLEET_CONNECTION }}\n        if: env.SLEET_CONNECTION != ''\n        run: |\n          dotnet tool update sleet -g --allow-downgrade --version $(curl -s --compressed ${{ vars.SLEET_FEED_URL }} | jq '.[\"sleet:version\"]' -r)        \n          sleet push bin --config none -f --verbose -p \"SLEET_FEED_CONTAINER=nuget\" -p \"SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}\" -p \"SLEET_FEED_TYPE=azure\" || echo \"No packages found\"\n\n  dotnet-format:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with: \n          submodules: recursive\n          fetch-depth: 0\n\n      - name: ⚙ dotnet\n        uses: devlooped/actions-dotnet-env@v1\n\n      - name: ✓ ensure format\n        run: |\n          dotnet format whitespace --verify-no-changes -v:diag --exclude ~/.nuget\n          dotnet format style --verify-no-changes -v:diag --exclude ~/.nuget\n"
  },
  {
    "path": ".github/workflows/changelog.config",
    "content": "usernames-as-github-logins=true\nissues_wo_labels=true\npr_wo_labels=true\nexclude-labels=bydesign,dependencies,duplicate,discussion,question,invalid,wontfix,need info,docs\nenhancement-label=:sparkles: Implemented enhancements:\nbugs-label=:bug: Fixed bugs:\nissues-label=:hammer: Other:\npr-label=:twisted_rightwards_arrows: Merged:\nunreleased=false\n"
  },
  {
    "path": ".github/workflows/changelog.yml",
    "content": "﻿name: changelog\non:\n  workflow_dispatch:\n  release:\n    types: [released]\n\njobs:\n  changelog:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🤖 defaults\n        uses: devlooped/actions-bot@v1\n        with:\n          name: ${{ secrets.BOT_NAME }}\n          email: ${{ secrets.BOT_EMAIL }}\n          gh_token: ${{ secrets.GH_TOKEN }}\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          \n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n          ref: main\n          token: ${{ env.GH_TOKEN }}\n          \n      - name: ⚙ ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: 3.0.3\n\n      - name: ⚙ changelog\n        run: |\n          gem install github_changelog_generator \n          github_changelog_generator --user ${GITHUB_REPOSITORY%/*} --project ${GITHUB_REPOSITORY##*/} --token $GH_TOKEN --o changelog.md --config-file .github/workflows/changelog.config\n\n      - name: 🚀 changelog\n        run: |\n          git add changelog.md\n          (git commit -m \"🖉 Update changelog with ${GITHUB_REF#refs/*/}\" && git push) || echo \"Done\""
  },
  {
    "path": ".github/workflows/combine-prs.yml",
    "content": "# Source: https://github.com/hrvey/combine-prs-workflow\n# Tweaks: regex support for branch\n\nname: '⛙ combine-prs'\n\non:\n  workflow_dispatch:\n    inputs:\n      branchExpression:\n        description: 'Regular expression to match against PR branches to find combinable PRs'\n        required: true\n        default: 'dependabot'\n      mustBeGreen:\n        description: 'Only combine PRs that are green (status is success)'\n        required: true\n        default: true\n      combineTitle:\n        description: 'Title of the combined PR'\n        required: true\n        default: '⬆️ Bump dependencies'\n      combineBranchName:\n        description: 'Name of the branch to combine PRs into'\n        required: true\n        default: 'combine-prs'\n      ignoreLabel:\n        description: 'Exclude PRs with this label'\n        required: true\n        default: 'nocombine'\n\njobs:\n  combine-prs:\n    name: ${{ github.event.inputs.combineBranchName }}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/github-script@v6\n        with:\n          github-token: ${{secrets.GITHUB_TOKEN}}\n          script: |\n            const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {\n              owner: context.repo.owner,\n              repo: context.repo.repo\n            });\n            const branchRegExp = new RegExp(`${{github.event.inputs.branchExpression}}`);\n            let branchesAndPRStrings = [];\n            let baseBranch = null;\n            let baseBranchSHA = null;\n            for (const pull of pulls) {\n              const branch = pull['head']['ref'];\n              console.log('Pull for branch: ' + branch);\n              if (branchRegExp.test(branch)) {\n                console.log('Branch matched: ' + branch);\n                let statusOK = true;\n                if(${{ github.event.inputs.mustBeGreen }}) {\n                  console.log('Checking green status: ' + branch);\n                  const stateQuery = `query($owner: String!, $repo: String!, $pull_number: Int!) {\n                    repository(owner: $owner, name: $repo) {\n                      pullRequest(number:$pull_number) {\n                        commits(last: 1) {\n                          nodes {\n                            commit {\n                              statusCheckRollup {\n                                state\n                              }\n                            }\n                          }\n                        }\n                      }\n                    }\n                  }`\n                  const vars = {\n                    owner: context.repo.owner,\n                    repo: context.repo.repo,\n                    pull_number: pull['number']\n                  };\n                  const result = await github.graphql(stateQuery, vars);\n                  const [{ commit }] = result.repository.pullRequest.commits.nodes;\n                  const state = commit.statusCheckRollup.state\n                  console.log('Validating status: ' + state);\n                  if(state != 'SUCCESS') {\n                    console.log('Discarding ' + branch + ' with status ' + state);\n                    statusOK = false;\n                  }\n                }\n                console.log('Checking labels: ' + branch);\n                const labels = pull['labels'];\n                for(const label of labels) {\n                  const labelName = label['name'];\n                  console.log('Checking label: ' + labelName);\n                  if(labelName == '${{ github.event.inputs.ignoreLabel }}') {\n                    console.log('Discarding ' + branch + ' with label ' + labelName);\n                    statusOK = false;\n                  }\n                }\n                if (statusOK) {\n                  console.log('Adding branch to array: ' + branch);\n                  const prString = '#' + pull['number'] + ' ' + pull['title'];\n                  branchesAndPRStrings.push({ branch, prString });\n                  baseBranch = pull['base']['ref'];\n                  baseBranchSHA = pull['base']['sha'];\n                }\n              }\n            }\n            if (branchesAndPRStrings.length == 0) {\n              core.setFailed('No PRs/branches matched criteria');\n              return;\n            }\n            if (branchesAndPRStrings.length == 1) {\n              core.setFailed('Only one PR/branch matched criteria');\n              return;\n            }\n\n            try {\n              await github.rest.git.createRef({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                ref: 'refs/heads/' + '${{ github.event.inputs.combineBranchName }}',\n                sha: baseBranchSHA\n              });\n            } catch (error) {\n              console.log(error);\n              core.setFailed('Failed to create combined branch - maybe a branch by that name already exists?');\n              return;\n            }\n            \n            let combinedPRs = [];\n            let mergeFailedPRs = [];\n            for(const { branch, prString } of branchesAndPRStrings) {\n              try {\n                await github.rest.repos.merge({\n                  owner: context.repo.owner,\n                  repo: context.repo.repo,\n                  base: '${{ github.event.inputs.combineBranchName }}',\n                  head: branch,\n                });\n                console.log('Merged branch ' + branch);\n                combinedPRs.push(prString);\n              } catch (error) {\n                console.log('Failed to merge branch ' + branch);\n                mergeFailedPRs.push(prString);\n              }\n            }\n            \n            console.log('Creating combined PR');\n            const combinedPRsString = combinedPRs.join('\\n');\n            let body = '⛙ Combined PRs:\\n' + combinedPRsString;\n            if(mergeFailedPRs.length > 0) {\n              const mergeFailedPRsString = mergeFailedPRs.join('\\n');\n              body += '\\n\\n⚠️ The following PRs were left out due to merge conflicts:\\n' + mergeFailedPRsString\n            }\n            await github.rest.pulls.create({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              title: '⛙ ${{github.event.inputs.combineTitle}}',\n              head: '${{ github.event.inputs.combineBranchName }}',\n              base: baseBranch,\n              body: body\n            });\n"
  },
  {
    "path": ".github/workflows/demos.yml",
    "content": "﻿name: demos\non: \n  push:\n    branches: [ main, dev, 'dev/*', 'feature/*', 'rel/*' ]\n    paths-ignore:\n      - changelog.md\n      - readme.md\n  pull_request:\n    types: [opened, synchronize, reopened]\n\nenv:\n  DOTNET_NOLOGO: true\n  PackOnBuild: true\n  GeneratePackageOnBuild: true\n  VersionPrefix: 42.42.${{ github.run_number }}\n  VersionLabel: ${{ github.ref }}\n  GH_TOKEN: ${{ secrets.GH_TOKEN }}\n  MSBUILDTERMINALLOGGER: auto\n\ndefaults:\n  run:\n    shell: pwsh\n\njobs:\n  demos:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n\n      - name: ⚙ dotnet\n        uses: devlooped/actions-dotnet-env@v1\n\n      - name: 🙏 build\n        run: dotnet build -m:1 -bl:build.binlog\n\n      - name: 🚀 demo\n        run: |\n          # detect and set the version of the SDK we just built\n          $version = gci bin | select -first 1 -expandproperty BaseName | %{ $_.Substring(11) }\n          pushd src/Demo\n          jq --arg version \"$version\" '.[\"msbuild-sdks\"].SmallSharp = $version' global.json > temp.json && mv temp.json global.json\n\n          # build with each top-level file as the active one\n          foreach ($file in gci *.cs) {\n            dotnet build -p:ActiveFile=$($file.Name)\n            if ($LASTEXITCODE -ne 0) {\n              Write-Error \"Build failed for $($file.Name)\"\n              exit $LASTEXITCODE\n            }\n          }\n          "
  },
  {
    "path": ".github/workflows/dotnet-env.yml",
    "content": "name: dotnet-env\non:\n  workflow_dispatch:\n  push:\n    branches: \n      - main\n    paths:\n      - '**/*.*proj'\n\njobs:\n  which-dotnet:\n    runs-on: ubuntu-latest \n    permissions:\n      contents: write\n      pull-requests: write\n\n    steps:\n      - name: 🤖 defaults\n        uses: devlooped/actions-bot@v1\n        with:\n          name: ${{ secrets.BOT_NAME }}\n          email: ${{ secrets.BOT_EMAIL }}\n          gh_token: ${{ secrets.GH_TOKEN }}\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with: \n          token: ${{ env.GH_TOKEN }}\n\n      - name: 🤌 dotnet\n        uses: devlooped/actions-which-dotnet@v1\n\n      - name: ✍ pull request\n        uses: peter-evans/create-pull-request@v7\n        with:\n          base: main\n          branch: which-dotnet\n          delete-branch: true\n          labels: dependencies\n          title: \"⚙ Update dotnet versions\"\n          body: \"Update dotnet versions\"\n          commit-message: \"Update dotnet versions\"\n          token: ${{ env.GH_TOKEN }}          "
  },
  {
    "path": ".github/workflows/dotnet-file.yml",
    "content": "# Synchronizes .netconfig-configured files with dotnet-file\nname: dotnet-file\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"0 0 * * *\"\n  push:\n    branches: [ 'dotnet-file' ]\n\nenv:\n  DOTNET_NOLOGO: true\n\njobs:\n  run:\n    permissions:\n      contents: write\n    uses: devlooped/oss/.github/workflows/dotnet-file-core.yml@main\n    secrets: \n      BOT_NAME: ${{ secrets.BOT_NAME }}\n      BOT_EMAIL: ${{ secrets.BOT_EMAIL }}\n      GH_TOKEN: ${{ secrets.GH_TOKEN }}"
  },
  {
    "path": ".github/workflows/includes.yml",
    "content": "name: +Mᐁ includes\non: \n  workflow_dispatch:\n  push:\n    branches:\n      - 'main'\n    paths:\n      - '**.md'\n      - '!changelog.md'\n      - 'osmfeula.txt'\n\njobs:\n  includes:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      - name: 🤖 defaults\n        uses: devlooped/actions-bot@v1\n        with:\n          name: ${{ secrets.BOT_NAME }}\n          email: ${{ secrets.BOT_EMAIL }}\n          gh_token: ${{ secrets.GH_TOKEN }}\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with: \n          token: ${{ env.GH_TOKEN }}\n\n      - name: +Mᐁ includes\n        uses: devlooped/actions-includes@v1\n\n      - name: 📝 OSMF EULA\n        shell: pwsh\n        run: |\n          $file = \"osmfeula.txt\"\n          $props = \"src/Directory.Build.props\"\n          if (-not (test-path $file) -or -not (test-path $props)) {\n            exit 0\n          }\n\n          $product = dotnet msbuild $props -getproperty:Product\n          if (-not $product) { \n            write-error 'To use OSMF EULA, ensure the $(Product) property is set in Directory.props'\n            exit 1\n          }\n          \n          ((get-content -raw $file) -replace '\\$product\\$',$product).trim() | set-content $file\n\n      - name: ✍ pull request\n        uses: peter-evans/create-pull-request@v8\n        with:\n          add-paths: |\n            **.md\n            *.txt\n          base: main\n          branch: markdown-includes\n          delete-branch: true\n          labels: dependencies\n          author: ${{ env.BOT_AUTHOR }}\n          committer: ${{ env.BOT_AUTHOR }}\n          commit-message: +Mᐁ includes\n          title: +Mᐁ includes\n          body: +Mᐁ includes\n          token: ${{ env.GH_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/pages.yml",
    "content": "# Workflow to cross-post a jekyll site (or GitHub Pages)\n# to another org/repo. \n# Required secrets in repository consuming this workflow:\n#   - PAGES_ORGANIZATION: the target organization to publish \n#     pages to. \n#   - PAGES_ACCESS_TOKEN: a token that is valid in the target \n#     org/repo for pushing the resulting site\n#   - PAGES_REPOSITORY: optional repository name under the \n#     target organization. Defaults to source repo name.\n\nname: pages\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n      - pages\n      - docs\n\nenv:\n  PAGES_ORGANIZATION: ${{ secrets.PAGES_ORGANIZATION }}\n  PAGES_REPOSITORY: ${{ secrets.PAGES_REPOSITORY }}\n\njobs:\n  gh-pages:\n    runs-on: ubuntu-latest\n    env:\n      PAGES_ORGANIZATION: ${{ secrets.PAGES_ORGANIZATION }}\n      PAGES_REPOSITORY: ${{ secrets.PAGES_REPOSITORY }}\n      PAGES_ACCESS_TOKEN: ${{ secrets.PAGES_ACCESS_TOKEN }}\n    steps:\n      - name: ✅ organization\n        if: env.PAGES_ORGANIZATION == ''\n        run: |\n          echo \"::error title=PAGES_ORGANIZATION secret is required.\"\n          exit 1\n\n      - name: ✅ token\n        if: env.PAGES_ACCESS_TOKEN == ''\n        run: |\n          echo \"::error title=PAGES_ACCESS_TOKEN secret is required.\"\n          exit 1\n\n      - name: 🤘 checkout\n        uses: actions/checkout@v2\n\n      - name: ⚙ jekyll\n        run: |\n          sudo gem install bundler\n          sudo bundle install\n\n      - name: 🖉 default repo\n        if: env.PAGES_REPOSITORY == ''\n        run: echo \"PAGES_REPOSITORY=${GITHUB_REPOSITORY#*/}\" >> $GITHUB_ENV\n\n      - name: 🙏 build\n        run: bundle exec jekyll build -b ${{ env.PAGES_REPOSITORY }}\n        env:\n          JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: ✓ commit\n        run: |\n          cd _site\n          git init\n          git add -A\n          git config --local user.email \"bot@clarius.org\"\n          git config --local user.name \"bot@clarius.org\"\n          git commit -m \"Publish pages from ${GITHUB_REPOSITORY}@${GITHUB_SHA:0:9}\"\n\n      - name: 🚀 push\n        uses: ad-m/github-push-action@v0.6.0\n        with:\n          github_token: ${{ env.PAGES_ACCESS_TOKEN }}\n          repository: ${{ env.PAGES_ORGANIZATION }}/${{ env.PAGES_REPOSITORY }}\n          branch: gh-pages\n          force: true\n          directory: ./_site"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "﻿# Builds a final release version and pushes to nuget.org \n# whenever a release is published.\n# Requires: secrets.NUGET_API_KEY\n\nname: publish\non:\n  release:\n    types: [prereleased, released]\n\nenv:\n  DOTNET_NOLOGO: true\n  Configuration: Release\n  PackOnBuild: true\n  GeneratePackageOnBuild: true\n  VersionLabel: ${{ github.ref }}\n  GH_TOKEN: ${{ secrets.GH_TOKEN }}\n  MSBUILDTERMINALLOGGER: auto\n  SLEET_FEED_URL: https://api.nuget.org/v3/index.json\n      \njobs:\n  publish:\n    runs-on: ${{ vars.PUBLISH_AGENT || 'ubuntu-latest' }}\n    steps:\n      - name: 🤘 checkout\n        uses: actions/checkout@v4\n        with: \n          submodules: recursive\n          fetch-depth: 0\n\n      - name: ⚙ dotnet\n        uses: devlooped/actions-dotnet-env@v1\n\n      - name: 🙏 build\n        run: dotnet build -m:1 -bl:build.binlog\n\n      - name: 🧪 test\n        shell: pwsh\n        run: dnx --yes retest -- --no-build\n\n      - name: 🐛 logs\n        uses: actions/upload-artifact@v4\n        if: runner.debug && always()\n        with:\n          name: logs\n          path: '*.binlog'\n\n      - name: 🚀 nuget\n        env:\n          NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}\n        if: ${{ env.NUGET_API_KEY != '' && github.event.action != 'prereleased' }}\n        working-directory: bin\n        run: dotnet nuget push *.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} --skip-duplicate\n\n      - name: 🚀 sleet\n        env:\n          SLEET_CONNECTION: ${{ secrets.SLEET_CONNECTION }}\n        if: env.SLEET_CONNECTION != ''\n        run: |\n          dotnet tool update sleet -g --allow-downgrade --version $(curl -s --compressed ${{ vars.SLEET_FEED_URL }} | jq '.[\"sleet:version\"]' -r)        \n          sleet push bin --config none -f --verbose -p \"SLEET_FEED_CONTAINER=nuget\" -p \"SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}\" -p \"SLEET_FEED_TYPE=azure\" || echo \"No packages found\"\n"
  },
  {
    "path": ".github/workflows/triage.yml",
    "content": "name: 'triage'\non:\n  schedule:\n    - cron: '42 0 * * *'\n\n  workflow_dispatch:\n    # Manual triggering through the GitHub UI, API, or CLI\n    inputs:\n      daysBeforeClose:\n        description: \"Days before closing stale or need info issues\"\n        required: true\n        default: \"30\"\n      daysBeforeStale:\n        description: \"Days before labeling stale\"\n        required: true\n        default: \"180\"\n      daysSinceClose:\n        description: \"Days since close to lock\"\n        required: true\n        default: \"30\"\n      daysSinceUpdate:\n        description: \"Days since update to lock\"\n        required: true\n        default: \"30\"\n\npermissions:\n  actions: write # For managing the operation state cache\n  issues: write\n  contents: read\n\njobs:\n  stale:\n    # Do not run on forks\n    if: github.repository_owner == 'devlooped' \n    runs-on: ubuntu-latest\n    steps:\n      - name: ⌛ rate\n        shell: pwsh\n        if: github.event_name != 'workflow_dispatch'\n        env:\n          GH_TOKEN: ${{ secrets.DEVLOOPED_TOKEN }}        \n        run: |\n          # add random sleep since we run on fixed schedule\n          $wait = get-random -max 180\n          echo \"Waiting random $wait seconds to start\"          \n          sleep $wait\n          # get currently authenticated user rate limit info\n          $rate = gh api rate_limit | convertfrom-json | select -expandproperty rate\n          # if we don't have at least 100 requests left, wait until reset\n          if ($rate.remaining -lt 100) {\n              $wait = ($rate.reset - (Get-Date (Get-Date).ToUniversalTime() -UFormat %s))\n              if ($wait -gt 300) {\n                  echo \"Rate limit remaining is $($rate.remaining), reset in $wait seconds (more than 5'). Aborting.\"\n                  exit 1\n              }\n              echo \"Rate limit remaining is $($rate.remaining), waiting $wait seconds to reset\"\n              sleep $wait\n              $rate = gh api rate_limit | convertfrom-json | select -expandproperty rate\n              echo \"Rate limit has reset to $($rate.remaining) requests\"\n          }\n        \n      - name: ✏️ stale labeler\n        # pending merge: https://github.com/actions/stale/pull/1176\n        uses: kzu/stale@c8450312ba97b204bf37545cb249742144d6ca69\n        with:\n          ascending: true # Process the oldest issues first\n          stale-issue-label: 'stale'\n          stale-issue-message: |\n            Due to lack of recent activity, this issue has been labeled as 'stale'. \n            It will be closed if no further activity occurs within ${{ fromJson(inputs.daysBeforeClose || 30  ) }} more days. \n            Any new comment will remove the label.\n          close-issue-message: |\n            This issue will now be closed since it has been labeled 'stale' without activity for ${{ fromJson(inputs.daysBeforeClose || 30  ) }} days.\n          days-before-stale: ${{ fromJson(inputs.daysBeforeStale || 180) }}  \n          days-before-close: ${{ fromJson(inputs.daysBeforeClose || 30  ) }}\n          days-before-pr-close: -1 # Do not close PRs labeled as 'stale'\n          exempt-all-milestones: true\n          exempt-all-assignees: true\n          exempt-issue-labels: priority,sponsor,backed\n          exempt-authors: kzu\n\n      - name: 🤘 checkout actions\n        uses: actions/checkout@v4\n        with:\n          repository: 'microsoft/vscode-github-triage-actions'\n          ref: v42\n\n      - name: ⚙ install actions\n        run: npm install --production\n\n      - name: 🔒 issues locker\n        uses: ./locker\n        with:\n          token: ${{ secrets.DEVLOOPED_TOKEN }}\n          ignoredLabel: priority\n          daysSinceClose:  ${{ fromJson(inputs.daysSinceClose  || 30) }}\n          daysSinceUpdate: ${{ fromJson(inputs.daysSinceUpdate || 30) }}\n\n      - name: 🔒 need info closer\n        uses: ./needs-more-info-closer\n        with:\n          token: ${{ secrets.DEVLOOPED_TOKEN }}\n          label: 'need info'\n          closeDays:  ${{ fromJson(inputs.daysBeforeClose  || 30) }}\n          closeComment: \"This issue has been closed automatically because it needs more information and has not had recent activity.\\n\\nHappy Coding!\"\n          pingDays: 80\n          pingComment: \"Hey @${assignee}, this issue might need further attention.\\n\\n@${author}, you can help us out by closing this issue if the problem no longer exists, or adding more information.\""
  },
  {
    "path": ".gitignore",
    "content": "bin\nobj\nartifacts\npack\nTestResults\nresults\nBenchmarkDotNet.Artifacts\n/app\n.vs\n.vscode\n.genaiscript\n.idea\nlocal.settings.json\n.env\n*.local\n\n*.suo\n*.sdf\n*.userprefs\n*.user\n*.nupkg\n*.metaproj\n*.tmp\n*.log\n*.cache\n*.binlog\n*.zip\n__azurite*.*\n__*__\n\n.nuget\n*.lock.json\n*.nuget.props\n*.nuget.targets\n\nnode_modules\n_site\n.jekyll-metadata\n.jekyll-cache\n.sass-cache\nGemfile.lock\npackage-lock.json\n"
  },
  {
    "path": ".netconfig",
    "content": "[file]\n\turl = https://github.com/devlooped/oss\n\turl = https://github.com/clarius/pages\n[file \".netconfig\"]\n\turl = https://github.com/devlooped/oss/blob/main/.netconfig\n    skip\n[file \"src/icon.png\"]\n\turl = https://github.com/devlooped/oss/blob/main/src/icon.png\n\tskip\n[file \"readme.md\"]\n\turl = https://github.com/devlooped/oss/blob/main/readme.md\n\tskip\n[file \".github/ISSUE_TEMPLATE/config.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/ISSUE_TEMPLATE/config.yml\n\tskip\n[file \"SponsorLink.sln\"]\n\turl = https://github.com/devlooped/oss/blob/main/SponsorLink.sln\n\tskip\n[file \".editorconfig\"]\n\turl = https://github.com/devlooped/oss/blob/main/.editorconfig\n\tetag = b5e919b472a52d4b522f86494f0f2c0ba74a6d9601454e20e4cbaf744317ff62\n\tweak\n\tsha = a62c45934ac2952f2f5d54d8aea4a7ebc1babaff\n[file \".gitattributes\"]\n\turl = https://github.com/devlooped/oss/blob/main/.gitattributes\n\tetag = 09cad18280ed04b67f7f87591e5481510df04d44c3403231b8af885664d8fd58\n\tweak\n\tsha = 4a9aa321c4982b83c185cf8dffed181ff84667d5\n[file \".github/FUNDING.yml\"]\n\turl = https://github.com/devlooped/.github/blob/main/.github/FUNDING.yml\n\tetag = a944c728facd033bbdfb4ff8d0ef10d0b3a457c277dc499458df0ffc7e6409da\n\tweak\n\tsha = 39f4c591716ff50dd035d2fade35e5822489ab7f\n[file \".github/dependabot.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/dependabot.yml\n\tetag = 3bf8d9214a15c049ca5cfe80d212a8cbe4753b8a638a9804ef73d34c7def9618\n\tweak\n\tsha = e733294084fb3e75d517a2e961e87df8faae7dc6\n[file \".github/workflows/build.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/build.yml\n\tetag = 851af098748f7cfa5bc3cfd4cc404a6de930532b59ceb2b3b535282c41226f3a\n\tweak\n\tsha = 5da103cfbc1c4f9b5f59cfa698d2afbd744a7525\n[file \".github/workflows/changelog.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.yml\n\tetag = ad1efa56d6024ee1add2bcda81a7e4e38d0e9069473c6ff70374d5ce06af1f5a\n\tweak\n\tsha = 5fb172362c767bef7c36478f1a6bdc264723f8f9\n[file \".github/workflows/publish.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/publish.yml\n\tetag = c60411d1aa4e98e7f69e2d34cbccb8eb7e387ec11f6f8e78ee8d8b92122d7025\n\tweak\n\tsha = 7f5f9ee9f362f7e8f951d618f8f799033550e687\n[file \".github/workflows/release-artifacts.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/release-artifacts.yml\n    skip\n[file \".gitignore\"]\n\turl = https://github.com/devlooped/oss/blob/main/.gitignore\n\tetag = 20a8b49d57024abbd85aac5b0020c30e5eb68e0384b2761e93727c8780c4a991\n\tweak\n\tsha = a225b7a9f609f26bcc24e0d84f663387be251a7d\n[file \"Directory.Build.rsp\"]\n\turl = https://github.com/devlooped/oss/blob/main/Directory.Build.rsp\n\tetag = 0ccae83fc51f400bfd7058170bfec7aba11455e24a46a0d7e6a358da6486e255\n\tweak\n\tsha = 0f7f7f7e8a29de9b535676f75fe7c67e629a5e8c\n[file \"_config.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/_config.yml\n\tetag = d608aa0ddaedc2d8a87260f50756e8d8314964ad4671b76bd085bcb458757010\n\tweak\n\tsha = 68b409c486842062e0de0e5b11e6fdb7cd12d6e2\n[file \"assets/css/style.scss\"]\n\turl = https://github.com/devlooped/oss/blob/main/assets/css/style.scss\n\tetag = f710d8919abfd5a8d00050b74ba7d0bb05c6d02e40842a3012eb96555c208504\n\tweak\n\tsha = 9db26e2710b084d219d6355339d822f159bf5780\n[file \"license.txt\"]\n\turl = https://github.com/devlooped/oss/blob/main/license.txt\n\tetag = 2c6335b37e4ae05eea7c01f5d0c9d82b49c488f868a8b5ba7bff7c6ff01f3994\n\tweak\n\tsha = 0683ee777d7d878d4bf013d7deea352685135a05\n[file \"src/Directory.Build.props\"]\n\turl = https://github.com/devlooped/oss/blob/main/src/Directory.Build.props\n\tetag = bd05f9f240823c0ac79ddfefe654061550c36f82dd94fa513b82900e92686a5f\n\tweak\n\tsha = 4b84c540df6f37c30fb38df7947d79871c34f036\n[file \"src/Directory.Build.targets\"]\n\turl = https://github.com/devlooped/oss/blob/main/src/Directory.Build.targets\n\tetag = 907682e5632a2ba430357e6e042a4ca33cb8c94a3a215d3091aa03f5958a4877\n\tweak\n\tsha = 4b84c540df6f37c30fb38df7947d79871c34f036\n[file \"src/kzu.snk\"]\n\turl = https://github.com/devlooped/oss/blob/main/src/kzu.snk\n\tskip\n[file \".github/workflows/pages.yml\"]\n\turl = https://github.com/clarius/pages/blob/main/.github/workflows/pages.yml\n\tetag = c52b3f0463b88abf696ddf2c6902675e0bc9d1e812bb317cb758221d75330b56\n\tweak\n\tsha = afcb0421af6507eba5ceba913b8fc37261efc085\n[file \"Gemfile\"]\n\turl = https://github.com/clarius/pages/blob/main/Gemfile\n\tetag = 3dd7febc8ae6760f19abfe787711f469c288cd803a6f1c545edec34264d48e71\n\tweak\n\tsha = 90fa16ed0e7300a78a38ee1d23c34a7e875aab27\n[file \".github/workflows/dotnet-file.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/dotnet-file.yml\n\tsha = 8fa147d4799d73819040736c399d0b1db2c2d86c\n\tetag = 1ca805a23656e99c03f9d478dba8ccef6e571f5de2ac0e9bb7e3c5216c99a694\n\tweak\n[file \".github/workflows/includes.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/includes.yml\n\tsha = 06628725a6303bb8c4cf3076a384fc982a91bc0b\n\tetag = 478f91d4126230e57cc601382da1ba23f9daa054645b4af89800d8dd862e64fd\n\tweak\n[file \".github/workflows/combine-prs.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/combine-prs.yml\n\tsha = c1610886eba42cb250e3894aed40c0a258cd383d\n\tetag = 598ee294649a44d4c5d5934416c01183597d08aa7db7938453fd2bbf52a4e64d\n\tweak\n[file \".github/workflows/changelog.config\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.config\n\tsha = 08d83cb510732f861416760d37702f9f55bd7f9e\n\tetag = 556a28914eeeae78ca924b1105726cdaa211af365671831887aec81f5f4301b4\n\tweak\n[file \".github/release.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/release.yml\n\tsha = 0c23e24704625cf75b2cb1fdc566cef7e20af313\n\tetag = 310df162242c95ed19ed12e3c96a65f77e558b46dced676ad5255eb12caafe75\n\tweak\n[file \".github/workflows/triage.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/triage.yml\n\tsha = 33000c0c4ab4eb4e0e142fa54515b811a189d55c\n\tetag = 152cd3a559c08da14d1da12a5262ba1d2e0ed6bed6d2eabf5bd209b0c35d8a75\n\tweak\n[file \".github/workflows/dotnet-file-core.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/dotnet-file-core.yml\n\tskip\n[file \".github/actions/dotnet/action.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/actions/dotnet/action.yml\n\tsha = f2b690ce307acb76c5b8d7faec1a5b971a93653e\n\tetag = 27ea11baa2397b3ec9e643a935832da97719c4e44215cfd135c49cad4c29373f\n\tweak\n[file \".github/workflows/dotnet-env.yml\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/workflows/dotnet-env.yml\n\tsha = 77e83f238196d2723640abef0c7b6f43994f9747\n\tetag = fcb9759a96966df40dcd24906fd328ddec05953b7e747a6bb8d0d1e4c3865274\n\tweak\n[file \"src/nuget.config\"]\n\turl = https://github.com/devlooped/oss/blob/main/src/nuget.config\n\tsha = 032439dbf180fca0539a5bd3a019f18ab3484b76\n\tetag = da7c0104131bd474b52fc9bc9f9bda6470e24ae38d4fb9f5c4f719bc01370ab5\n\tweak\n[file \"readme.tmp.md\"]\n\turl = https://github.com/devlooped/oss/blob/main/readme.tmp.md\n\tskip\n[file \"oss.cs\"]\n\turl = https://github.com/devlooped/oss/blob/main/oss.cs\n\tskip\n[file \".github/copilot-instructions.md\"]\n\turl = https://github.com/devlooped/oss/blob/main/.github/copilot-instructions.md\n\tetag = 6ee650d118a57494d3545d54718ccaa5257b09d54504e9c21514fe596edd9678\n\tweak\n"
  },
  {
    "path": "Directory.Build.rsp",
    "content": "# See https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files\n-nr:false\n-m:1\n-v:m\n-clp:Summary;ForceNoAlign\n"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'github-pages', '~> 231', group: :jekyll_plugins\n"
  },
  {
    "path": "SmallSharp.slnx",
    "content": "<Solution>\n  <Project Path=\"src/SmallSharp/SmallSharp.csproj\" />\n</Solution>\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-slate\n\nexclude: [ 'src/', '*.sln', '*.slnx', 'Gemfile*', '*.rsp' ]\n"
  },
  {
    "path": "assets/css/style.scss",
    "content": "---\n---\n\n@import \"jekyll-theme-slate\";\n\n.inner {\n    max-width: 960px;\n}\n\npre, code {\n    background-color: unset;\n    font-size: unset;\n}\n\n code {\n    font-size: 0.80em;\n}\n\nh1 > img {\n    border: unset;\n    box-shadow: unset;\n    vertical-align: middle;\n    -moz-box-shadow: unset;\n    -o-box-shadow: unset;\n    -ms-box-shadow: unset;\n}\n"
  },
  {
    "path": "changelog.md",
    "content": "# Changelog\n\n## [v2.3.1](https://github.com/devlooped/SmallSharp/tree/v2.3.1) (2026-04-09)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.3.0...v2.3.1)\n\n:sparkles: Implemented enhancements:\n\n- Add support for linked files [\\#174](https://github.com/devlooped/SmallSharp/pull/174) (@kzu)\n\n## [v2.3.0](https://github.com/devlooped/SmallSharp/tree/v2.3.0) (2025-12-17)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.5...v2.3.0)\n\n:sparkles: Implemented enhancements:\n\n- Ensure properties are always set in props+targets [\\#171](https://github.com/devlooped/SmallSharp/pull/171) (@kzu)\n\n## [v2.2.5](https://github.com/devlooped/SmallSharp/tree/v2.2.5) (2025-10-16)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.4...v2.2.5)\n\n## [v2.2.4](https://github.com/devlooped/SmallSharp/tree/v2.2.4) (2025-09-24)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.3...v2.2.4)\n\n:sparkles: Implemented enhancements:\n\n- Ensure when running from VS, output supports UTF-8 [\\#161](https://github.com/devlooped/SmallSharp/pull/161) (@kzu)\n\n## [v2.2.3](https://github.com/devlooped/SmallSharp/tree/v2.2.3) (2025-09-24)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.2...v2.2.3)\n\n:sparkles: Implemented enhancements:\n\n- Switch to $\\(Start\\) to select startup file [\\#160](https://github.com/devlooped/SmallSharp/pull/160) (@kzu)\n\n:bug: Fixed bugs:\n\n- Don't warn during restore about duplicate package refs [\\#159](https://github.com/devlooped/SmallSharp/pull/159) (@kzu)\n\n:twisted_rightwards_arrows: Merged:\n\n- Upgrade to latest SLNX format [\\#158](https://github.com/devlooped/SmallSharp/pull/158) (@kzu)\n\n## [v2.2.2](https://github.com/devlooped/SmallSharp/tree/v2.2.2) (2025-09-24)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.1...v2.2.2)\n\n:twisted_rightwards_arrows: Merged:\n\n- Emit package references in SDK mode too [\\#157](https://github.com/devlooped/SmallSharp/pull/157) (@kzu)\n\n## [v2.2.1](https://github.com/devlooped/SmallSharp/tree/v2.2.1) (2025-09-10)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.2.0...v2.2.1)\n\n:bug: Fixed bugs:\n\n- Fix error when file has no package references [\\#153](https://github.com/devlooped/SmallSharp/pull/153) (@kzu)\n\n:twisted_rightwards_arrows: Merged:\n\n- Improve directive matching by using named groups [\\#154](https://github.com/devlooped/SmallSharp/pull/154) (@kzu)\n\n## [v2.2.0](https://github.com/devlooped/SmallSharp/tree/v2.2.0) (2025-09-10)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.1.0...v2.2.0)\n\n:sparkles: Implemented enhancements:\n\n- Align \\#:property Name=Value with RC syntax [\\#152](https://github.com/devlooped/SmallSharp/pull/152) (@kzu)\n\n:bug: Fixed bugs:\n\n- We only ever support C\\#, so use .cs extension [\\#151](https://github.com/devlooped/SmallSharp/pull/151) (@kzu)\n\n## [v2.1.0](https://github.com/devlooped/SmallSharp/tree/v2.1.0) (2025-09-04)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.1.0-beta...v2.1.0)\n\n## [v2.1.0-beta](https://github.com/devlooped/SmallSharp/tree/v2.1.0-beta) (2025-09-04)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.1.0-alpha...v2.1.0-beta)\n\n:sparkles: Implemented enhancements:\n\n- Improve automatic restore support in SDK mode [\\#147](https://github.com/devlooped/SmallSharp/pull/147) (@kzu)\n\n:twisted_rightwards_arrows: Merged:\n\n- Demo can now rely on plain build working [\\#145](https://github.com/devlooped/SmallSharp/pull/145) (@kzu)\n\n## [v2.1.0-alpha](https://github.com/devlooped/SmallSharp/tree/v2.1.0-alpha) (2025-09-01)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.0.0...v2.1.0-alpha)\n\n:sparkles: Implemented enhancements:\n\n- Update package references instead of emitting duplicates [\\#140](https://github.com/devlooped/SmallSharp/issues/140)\n- SmallSharp generated targets are not imported from dotnet build/run [\\#139](https://github.com/devlooped/SmallSharp/issues/139)\n- Add support for \\#:sdk directive and no restore failures [\\#144](https://github.com/devlooped/SmallSharp/pull/144) (@kzu)\n- Ensure dotnet build works too [\\#141](https://github.com/devlooped/SmallSharp/pull/141) (@kzu)\n\n:hammer: Other:\n\n- Add support for \\#:sdk directive [\\#143](https://github.com/devlooped/SmallSharp/issues/143)\n\n## [v2.0.0](https://github.com/devlooped/SmallSharp/tree/v2.0.0) (2025-07-22)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.0.0-rc...v2.0.0)\n\n## [v2.0.0-rc](https://github.com/devlooped/SmallSharp/tree/v2.0.0-rc) (2025-07-22)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v2.0.0-beta...v2.0.0-rc)\n\n## [v2.0.0-beta](https://github.com/devlooped/SmallSharp/tree/v2.0.0-beta) (2025-07-22)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.3.0...v2.0.0-beta)\n\n:sparkles: Implemented enhancements:\n\n- Fix issue with properties containing spaces [\\#130](https://github.com/devlooped/SmallSharp/pull/130) (@kzu)\n- Add support for \\#:property directive [\\#129](https://github.com/devlooped/SmallSharp/pull/129) (@kzu)\n- Clean launchsettings.json if explicitly cleaned [\\#128](https://github.com/devlooped/SmallSharp/pull/128) (@kzu)\n- Add run file \\#:package support [\\#125](https://github.com/devlooped/SmallSharp/pull/125) (@kzu)\n\n## [v1.3.0](https://github.com/devlooped/SmallSharp/tree/v1.3.0) (2025-07-19)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.2.0...v1.3.0)\n\n:sparkles: Implemented enhancements:\n\n- Remove brittle active document tracking [\\#122](https://github.com/devlooped/SmallSharp/pull/122) (@kzu)\n\n## [v1.2.0](https://github.com/devlooped/SmallSharp/tree/v1.2.0) (2024-07-17)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.7...v1.2.0)\n\n:sparkles: Implemented enhancements:\n\n- Make sure startup file is an up-to-date check input [\\#115](https://github.com/devlooped/SmallSharp/pull/115) (@kzu)\n- Make sure file names are sorted alphabetically [\\#112](https://github.com/devlooped/SmallSharp/pull/112) (@kzu)\n\n## [v1.1.7](https://github.com/devlooped/SmallSharp/tree/v1.1.7) (2022-11-16)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.6...v1.1.7)\n\n:sparkles: Implemented enhancements:\n\n- Make SmallSharp a development dependency [\\#95](https://github.com/devlooped/SmallSharp/issues/95)\n\n## [v1.1.6](https://github.com/devlooped/SmallSharp/tree/v1.1.6) (2022-11-16)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.5...v1.1.6)\n\n:twisted_rightwards_arrows: Merged:\n\n- +M▼ includes [\\#79](https://github.com/devlooped/SmallSharp/pull/79) (@github-actions[bot])\n- +M▼ includes [\\#76](https://github.com/devlooped/SmallSharp/pull/76) (@github-actions[bot])\n\n## [v1.1.5](https://github.com/devlooped/SmallSharp/tree/v1.1.5) (2022-02-03)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.4...v1.1.5)\n\n:sparkles: Implemented enhancements:\n\n- Simplify editing of launchSettings.json by using Devlooped.JsonPoke [\\#64](https://github.com/devlooped/SmallSharp/issues/64)\n\n## [v1.1.4](https://github.com/devlooped/SmallSharp/tree/v1.1.4) (2021-07-05)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.2...v1.1.4)\n\n:hammer: Other:\n\n- Include package readme for better discoverability in gallery [\\#49](https://github.com/devlooped/SmallSharp/issues/49)\n\n## [v1.1.2](https://github.com/devlooped/SmallSharp/tree/v1.1.2) (2021-05-17)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.1...v1.1.2)\n\n:sparkles: Implemented enhancements:\n\n- When trying to attach to the IDE ActiveDocument, increase wait between retries [\\#41](https://github.com/devlooped/SmallSharp/issues/41)\n- Populate launchSettings with candidate top-level compile files [\\#40](https://github.com/devlooped/SmallSharp/issues/40)\n\n## [v1.1.1](https://github.com/devlooped/SmallSharp/tree/v1.1.1) (2021-04-08)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.1.0...v1.1.1)\n\n:bug: Fixed bugs:\n\n- Failure with VS 16.10 preview [\\#36](https://github.com/devlooped/SmallSharp/issues/36)\n\n:hammer: Other:\n\n- Ensure Properties folder exists before updating the launchSettings.json [\\#33](https://github.com/devlooped/SmallSharp/issues/33)\n\n:twisted_rightwards_arrows: Merged:\n\n- Ensure the directory for launchSettings.json exists [\\#34](https://github.com/devlooped/SmallSharp/pull/34) (@kzu)\n\n## [v1.1.0](https://github.com/devlooped/SmallSharp/tree/v1.1.0) (2021-02-15)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.0.3...v1.1.0)\n\n:sparkles: Implemented enhancements:\n\n- Adding new C\\# file should result in a new startup file [\\#9](https://github.com/devlooped/SmallSharp/issues/9)\n\n:twisted_rightwards_arrows: Merged:\n\n- 🗁 When adding new file, set as startup file [\\#23](https://github.com/devlooped/SmallSharp/pull/23) (@kzu)\n\n## [v1.0.3](https://github.com/devlooped/SmallSharp/tree/v1.0.3) (2021-02-12)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.0.2...v1.0.3)\n\n:sparkles: Implemented enhancements:\n\n- Set up Discussions for the project [\\#21](https://github.com/devlooped/SmallSharp/issues/21)\n\n:bug: Fixed bugs:\n\n- Fix icon that was replaced with clarius.org one [\\#22](https://github.com/devlooped/SmallSharp/issues/22)\n\n## [v1.0.2](https://github.com/devlooped/SmallSharp/tree/v1.0.2) (2021-02-12)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.0.1...v1.0.2)\n\n:sparkles: Implemented enhancements:\n\n- Allow consuming CI/main package from the sleet feed [\\#19](https://github.com/devlooped/SmallSharp/issues/19)\n\n:bug: Fixed bugs:\n\n- When changing active files quickly, opening startup file may fail [\\#18](https://github.com/devlooped/SmallSharp/issues/18)\n- Debug.Fail dialogs should not be shown on publicly released packages [\\#17](https://github.com/devlooped/SmallSharp/issues/17)\n- Renaming file crashes Visual Studio [\\#15](https://github.com/devlooped/SmallSharp/issues/15)\n\n:twisted_rightwards_arrows: Merged:\n\n- Improve resiliency when invoking DTE [\\#20](https://github.com/devlooped/SmallSharp/pull/20) (@kzu)\n- typo: fix roslyn [\\#14](https://github.com/devlooped/SmallSharp/pull/14) (@alastairtree)\n\n## [v1.0.1](https://github.com/devlooped/SmallSharp/tree/v1.0.1) (2020-11-20)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v1.0.0...v1.0.1)\n\n:sparkles: Implemented enhancements:\n\n- How to install?  [\\#10](https://github.com/devlooped/SmallSharp/issues/10)\n\n## [v1.0.0](https://github.com/devlooped/SmallSharp/tree/v1.0.0) (2020-11-18)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v0.3.0...v1.0.0)\n\n:twisted_rightwards_arrows: Merged:\n\n- Open startup file upon selection [\\#8](https://github.com/devlooped/SmallSharp/pull/8) (@kzu)\n- Version improvements [\\#6](https://github.com/devlooped/SmallSharp/pull/6) (@kzu)\n- Push and add CI package version for dogfooding purposes. [\\#5](https://github.com/devlooped/SmallSharp/pull/5) (@kzu)\n\n## [v0.3.0](https://github.com/devlooped/SmallSharp/tree/v0.3.0) (2020-10-07)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/v0.2.0...v0.3.0)\n\n## [v0.2.0](https://github.com/devlooped/SmallSharp/tree/v0.2.0) (2020-10-01)\n\n[Full Changelog](https://github.com/devlooped/SmallSharp/compare/b42f339e41771204a132fda34b061236b78c8511...v0.2.0)\n\n\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*\n"
  },
  {
    "path": "license.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) Daniel Cazzulino and Contributors\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\n"
  },
  {
    "path": "osmfeula.txt",
    "content": "End User License Agreement\n\nThis Open Source Maintenance Fee Agreement (\"Agreement\") is a legal agreement\nbetween you (\"User\") and Devlooped (\"Project\") for the use of\nSmallSharp (\"Software\"), an open source software project licensed under\nthe MIT License (\"OSI License\"), an OSI-approved open source license.\nProject offers a Binary Release of the Software to Users in exchange for a\nmaintenance fee (\"Fee\"). \"Binary Release\" refers to pre-compiled executable\nversions of the Software provided by Project. By accessing or using the\nBinary Release, User agrees to be bound by the terms of this Agreement.\n\n1. Applicability\n\nProject agrees to provide User with the Binary Release in exchange for the\nFees outlined in Section 2, subject to the terms of this Agreement. The Fee\napplies only to Users that generate revenue by the Software.\nNon-revenue-generating use of the Software is exempt from this Fee. In\naddition, Users who pay separate support and/or maintenance fees to the\nmaintainers of the Software are exempt from the Fee outlined in this\nAgreement. This distinction ensures that duplicate fees are not imposed,\npromoting fairness and consistency while respecting alternative support\narrangements.\n\n2. Monthly Fee and Payment Terms\n\nRevenue-generating Users required to pay the Fee shall follow the payment\nterms set forth by the Project. Failure to comply with these terms may result\nin suspending access to the Binary Release. However, this does not restrict\nthe User from obtaining or redistributing binaries from other sources or\nself-compiling them.\n\n3. Nature of the Fee\n\nThe Fee is not a license fee. The Software's source code is licensed to User\nunder the OSI License and remains freely distributable under the terms of the\nOSI License and any applicable open-source licenses.\n\n4. Conflicts with OSI License\n\nTo the extent any term of this Agreement conflicts with User's rights\nunder the OSI License regarding the Software, the OSI License shall govern.\nThis Agreement applies only to the Binary Release and does not limit User's\nability to access, modify, or distribute the Software's source code or\nself-compiled binaries. User may independently compile binaries from the\nSoftware's source code without this Agreement, subject to OSI License terms.\nUser may redistribute the Binary Release received under this Agreement,\nprovided such redistribution complies with the OSI License (e.g., including\ncopyright and permission notices). This Agreement imposes no additional\nrestrictions on such rights.\n\n5. Disclaimer of Warranty and Limitation of Liability\n\nTHE SOFTWARE AND BINARY RELEASE ARE PROVIDED BY THE PROJECT \"AS IS\" AND ANY\nEXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THE SOFTWARE AND BINARY RELEASE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "readme.md",
    "content": "![Icon](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/icon-32.png) SmallSharp\n============\n\n[![Version](https://img.shields.io/nuget/v/SmallSharp.svg?color=royalblue)](https://www.nuget.org/packages/SmallSharp) \n[![Downloads](https://img.shields.io/nuget/dt/SmallSharp?color=darkmagenta)](https://www.nuget.org/packages/SmallSharp) \n[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](https://github.com/devlooped/SmallSharp/blob/main/osmfeula.txt)\n[![OSS](https://img.shields.io/github/license/devlooped/SmallSharp.svg?color=blue)](https://github.com/devlooped/SmallSharp/blob/main/license.txt) \n\n<!-- #description -->\nCreate, edit and run multiple C# file-based apps in the same project in the IDE, honoring per-file `#:package` \nreferences, `#:property` project values and even `#:sdk` 😍\n<!-- #description -->\n\n<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->\n## Open Source Maintenance Fee\n\nTo ensure the long-term sustainability of this project, users of this package who generate \nrevenue must pay an [Open Source Maintenance Fee](https://opensourcemaintenancefee.org). \nWhile the source code is freely available under the terms of the [License](license.txt), \nthis package and other aspects of the project require [adherence to the Maintenance Fee](osmfeula.txt).\n\nTo pay the Maintenance Fee, [become a Sponsor](https://github.com/sponsors/devlooped) at the proper \nOSMF tier. A single fee covers all of [Devlooped packages](https://www.nuget.org/profiles/Devlooped).\n\n<!-- https://github.com/devlooped/.github/raw/main/osmf.md -->\n\n<!-- #content -->\n## Overview\n\nC# [top-level programs](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) \nallow a very intuitive, simple and streamlined experience for quickly spiking or learning C#. \nThe addition of [file-based apps](https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/) in \n.NET 10 [takes this further](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps) by allowing package references and even MSBuild properties to be \nspecified per file:\n\n```csharp\n#:package Humanizer@2.14.1\n#:property ImplicitUsings=true\n#:property Nullable=enable\n\nusing Humanizer;\n\nvar dotNet9Released = DateTimeOffset.Parse(\"2024-12-03\");\nvar since = DateTimeOffset.Now - dotNet9Released;\n\nConsole.WriteLine($\"It has been {since.Humanize()} since .NET 9 was released.\");\n```\n\nEditing these standalone files in VSCode, however, is suboptimal compared with the full C# \nexperience in Visual Studio. In Visual Studio, though, you can only have one top-level program \nin a project, and as of now, you cannot leverage the `#:package` and `#:property` directives \nat all.\n\n**SmallSharp** allows dynamically selecting the file to run, right from the Start button/dropdown \n(for compilation and launch/debug). It also automatically restores the `#:package` references so \nthe project system can resolve them, and even emits the `#:property` directives if present to customize \nthe build as needed.\n\n![start button](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/launchSettings.png)\n\nThis list is automatically kept in sync as you add more `.cs` files to the project. When you select \none target C# file, that becomes the only top-level program to be compiled, so you don't have to \nmodify any of the others since they automatically become *None* items. \n\n> [!TIP]\n> An initial build after selection change migh be needed to restore the packages and compile the \n> selected file, unless you're using the SDK mode for SmallSharp (see below).\n\nAll compile files directly under the project directory root are considered top-level programs for \nselection and compilation purposes. If you need to share code among them, you can place additional \nfiles in subdirectories and those will behave like normal compile items.\n\n## Usage\n\nSmallSharp works by just installing the \n[SmallSharp](https://nuget.org/packages/SmallSharp) nuget package in a C# console project \nand adding a couple extra properties to the project file:\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <!-- 👇 allows c# file to override the TF via a #:property -->\n    <TargetFramework Condition=\"$(TargetFramework) == ''\">net10.0</TargetFramework>\n\n    <!-- 👇 additional properties required in package mode -->\n    <ImportProjectExtensionProps>true</ImportProjectExtensionProps>\n    <ImportProjectExtensionTargets>true</ImportProjectExtensionTargets>   \n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"SmallSharp\" Version=\"*\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n</Project>\n```\n\nThere are some limitations with this mode, however: \n* You cannot use the `#:sdk` [directive](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps) \n  to specify a different SDK per file, since the project file already specifies one.\n* CLI-based builds may require multiple passes to restore and build the selected file, since \n  the package is only restored after the first build.\n* You must add ImportProjectExtensionProps/ImportProjectExtensionTargets manually, polluting the \n  project file.\n\nSo the recommended way to use SmallSharp is via the SDK mode, which results in a more streamlined \nand seamless experience across IDE and CLI builds:\n\n```xml\n<Project Sdk=\"SmallSharp/2.2.3\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <!-- 👇 allows c# file to override the TF via a #:property -->\n    <TargetFramework Condition=\"$(TargetFramework) == ''\">net10.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n```\n\nThe SDK mode will always produce a successful build in a single `dotnet build` pass even if you \nchange the `ActiveFile` between builds.\n\n> [!IMPORTANT]\n> If no `#:sdk` directive is provided by a specific C# file-based app, the `Microsoft.NET.SDK` will be \n> used by default in this SDK mode.\n\nKeep adding as many top-level programs as you need, and switch between them easily by simply \nselecting the desired file from the Start button dropdown.\n\nWhen running from the command-line, you can select the file to run by passing it as an argument to `dotnet run`:\n\n```bash\ndotnet run -p:start=program1.cs\n```\n\nYou can also use the shortcut `-p:s=[FILE]`.\n\n## How It Works\n\nThis nuget package leverages in concert the following standalone and otherwise \nunrelated features of the compiler, nuget and MSBuild:\n\n1. The C# compiler only allows one top-level program per compilation.\n2. Launch profiles (the entries in the Run dropdown) are populated from the Properties\\launchSettings.json file\n3. Whenever changed, the dropdown selection is persisted as the `$(ActiveDebugProfile)` MSBuild property in a file \n   named after the project with the `.user` extension\n4. This file is imported before NuGet-provided MSBuild targets\n5. VS ignores `#:` directives when adding the flag `FileBasedProgram` to the `$(Features)` project property.\n\nUsing the above features in concert, **SmallSharp** essentially does the following:\n\n* Emit top-level files as a `launchSettings.json` profile and set the `$(ActiveDebugProfile)`.\n\n* Exclude `.cs` files at the project level from being included as `<Compile>` by the default SDK \n  includes and include them explicitly as `<None>` instead so they show up in the solution explorer. \n  This prevents the compiler from causing an error for multiple top-level programs.\n\n* Explicitly include as `<Compile>` only the `$(ActiveDebugProfile)` property value.\n\n* Emit `#:package` and `#:property` directive to an automatically imported `obj\\SmallSharp.targets` file\n\n* SmallSharp MSBuild SDK automatically imports the `SmallSharp.targets` file, which causes a new \n  restore to automatically happen in Visual Studio, bringing all required dependencies automatically.\n\nThis basically mean that this it will also work consistently if you use `dotnet run` from the command-line, \nsince the \"Main\" file selection is performed exclusively via MSBuild item manipulation.\n\n> [!TIP]\n> It is recommended to keep the project file to its bare minimum, usually having just the SmallSharp \n> SDK reference, and do all project/package references in the top-level files using the `#:package` and \n> `#:property` directives for improved isolation between the different file-based apps.\n\n![run humanizer file](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/runfile1.png)\n\n![run mcp file](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/runfile2.png)\n<!-- #content -->\n\n<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->\n# Sponsors \n\n<!-- sponsors.md -->\n[![Clarius Org](https://avatars.githubusercontent.com/u/71888636?v=4&s=39 \"Clarius Org\")](https://github.com/clarius)\n[![MFB Technologies, Inc.](https://avatars.githubusercontent.com/u/87181630?v=4&s=39 \"MFB Technologies, Inc.\")](https://github.com/MFB-Technologies-Inc)\n[![Khamza Davletov](https://avatars.githubusercontent.com/u/13615108?u=11b0038e255cdf9d1940fbb9ae9d1d57115697ab&v=4&s=39 \"Khamza Davletov\")](https://github.com/khamza85)\n[![SandRock](https://avatars.githubusercontent.com/u/321868?u=99e50a714276c43ae820632f1da88cb71632ec97&v=4&s=39 \"SandRock\")](https://github.com/sandrock)\n[![DRIVE.NET, Inc.](https://avatars.githubusercontent.com/u/15047123?v=4&s=39 \"DRIVE.NET, Inc.\")](https://github.com/drivenet)\n[![Keith Pickford](https://avatars.githubusercontent.com/u/16598898?u=64416b80caf7092a885f60bb31612270bffc9598&v=4&s=39 \"Keith Pickford\")](https://github.com/Keflon)\n[![Thomas Bolon](https://avatars.githubusercontent.com/u/127185?u=7f50babfc888675e37feb80851a4e9708f573386&v=4&s=39 \"Thomas Bolon\")](https://github.com/tbolon)\n[![Kori Francis](https://avatars.githubusercontent.com/u/67574?u=3991fb983e1c399edf39aebc00a9f9cd425703bd&v=4&s=39 \"Kori Francis\")](https://github.com/kfrancis)\n[![Reuben Swartz](https://avatars.githubusercontent.com/u/724704?u=2076fe336f9f6ad678009f1595cbea434b0c5a41&v=4&s=39 \"Reuben Swartz\")](https://github.com/rbnswartz)\n[![Jacob Foshee](https://avatars.githubusercontent.com/u/480334?v=4&s=39 \"Jacob Foshee\")](https://github.com/jfoshee)\n[![](https://avatars.githubusercontent.com/u/33566379?u=bf62e2b46435a267fa246a64537870fd2449410f&v=4&s=39 \"\")](https://github.com/Mrxx99)\n[![Eric Johnson](https://avatars.githubusercontent.com/u/26369281?u=41b560c2bc493149b32d384b960e0948c78767ab&v=4&s=39 \"Eric Johnson\")](https://github.com/eajhnsn1)\n[![Jonathan ](https://avatars.githubusercontent.com/u/5510103?u=98dcfbef3f32de629d30f1f418a095bf09e14891&v=4&s=39 \"Jonathan \")](https://github.com/Jonathan-Hickey)\n[![Ken Bonny](https://avatars.githubusercontent.com/u/6417376?u=569af445b6f387917029ffb5129e9cf9f6f68421&v=4&s=39 \"Ken Bonny\")](https://github.com/KenBonny)\n[![Simon Cropp](https://avatars.githubusercontent.com/u/122666?v=4&s=39 \"Simon Cropp\")](https://github.com/SimonCropp)\n[![agileworks-eu](https://avatars.githubusercontent.com/u/5989304?v=4&s=39 \"agileworks-eu\")](https://github.com/agileworks-eu)\n[![Zheyu Shen](https://avatars.githubusercontent.com/u/4067473?v=4&s=39 \"Zheyu Shen\")](https://github.com/arsdragonfly)\n[![Vezel](https://avatars.githubusercontent.com/u/87844133?v=4&s=39 \"Vezel\")](https://github.com/vezel-dev)\n[![ChilliCream](https://avatars.githubusercontent.com/u/16239022?v=4&s=39 \"ChilliCream\")](https://github.com/ChilliCream)\n[![4OTC](https://avatars.githubusercontent.com/u/68428092?v=4&s=39 \"4OTC\")](https://github.com/4OTC)\n[![domischell](https://avatars.githubusercontent.com/u/66068846?u=0a5c5e2e7d90f15ea657bc660f175605935c5bea&v=4&s=39 \"domischell\")](https://github.com/DominicSchell)\n[![Adrian Alonso](https://avatars.githubusercontent.com/u/2027083?u=129cf516d99f5cb2fd0f4a0787a069f3446b7522&v=4&s=39 \"Adrian Alonso\")](https://github.com/adalon)\n[![torutek](https://avatars.githubusercontent.com/u/33917059?v=4&s=39 \"torutek\")](https://github.com/torutek)\n[![mccaffers](https://avatars.githubusercontent.com/u/16667079?u=110034edf51097a5ee82cb6a94ae5483568e3469&v=4&s=39 \"mccaffers\")](https://github.com/mccaffers)\n[![Seika Logiciel](https://avatars.githubusercontent.com/u/2564602?v=4&s=39 \"Seika Logiciel\")](https://github.com/SeikaLogiciel)\n[![Andrew Grant](https://avatars.githubusercontent.com/devlooped-user?s=39 \"Andrew Grant\")](https://github.com/wizardness)\n[![Lars](https://avatars.githubusercontent.com/u/1727124?v=4&s=39 \"Lars\")](https://github.com/latonz)\n[![prime167](https://avatars.githubusercontent.com/u/3722845?v=4&s=39 \"prime167\")](https://github.com/prime167)\n\n\n<!-- sponsors.md -->\n[![Sponsor this project](https://avatars.githubusercontent.com/devlooped-sponsor?s=118 \"Sponsor this project\")](https://github.com/sponsors/devlooped)\n\n[Learn more about GitHub Sponsors](https://github.com/sponsors)\n\n<!-- https://github.com/devlooped/sponsors/raw/main/footer.md -->\n"
  },
  {
    "path": "src/Demo/.gitignore",
    "content": "Demo.sln"
  },
  {
    "path": "src/Demo/Demo.csproj",
    "content": "﻿<Project Sdk=\"SmallSharp\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Update=\"nuget.config;global.json\" Visible=\"false\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Demo/Hello.cs",
    "content": "#:property ImplicitUsings=true\n#:package Spectre.Console@0.51.*\n\nusing Spectre.Console;\n\nAnsiConsole.MarkupLine(\":globe_showing_americas: Hello, World!\");"
  },
  {
    "path": "src/Demo/Humanizer.cs",
    "content": "﻿#:property ImplicitUsings=true\n#:property Nullable=enable\n#:package Humanizer@2.14.1\n\nusing Humanizer;\n\nvar dotNet9Released = DateTimeOffset.Parse(\"2024-12-03\");\nvar since = DateTimeOffset.Now - dotNet9Released;\n\nConsole.WriteLine($\"It has been {since.Humanize()} since .NET 9 was released.\");"
  },
  {
    "path": "src/Demo/Mcp.cs",
    "content": "#:property Title=LaTeX to Image MCP\n#:property Version=0.5.0\n#:property ImplicitUsings=true\n#:package Smith@0.2.5\n#:package DotNetConfig.Configuration@1.2.*\n#:package ModelContextProtocol@0.3.0-preview.*\n#:package Microsoft.Extensions.Http@9.*\n\nusing ModelContextProtocol.Protocol;\nusing ModelContextProtocol.Server;\n\nvar builder = App.CreateBuilder(args);\nbuilder.Configuration.AddDotNetConfig();\n\nvar initialized = false;\nbool? darkMode = bool.TryParse(builder.Configuration[\"latex:darkMode\"], out var dm) ? dm : null;\nstring? fontSize = builder.Configuration[\"latex:fontSize\"];\n// See https://editor.codecogs.com/docs/4-LaTeX_rendering.php#overview_anchor\nvar fonts = new Dictionary<string, string>\n{\n    { \"Tiny\", \"tiny\" },\n    { \"Small\", \"small\" },\n    { \"Large\", \"large\" },\n    { \"LARGE\", \"LARGE\" },\n    { \"Huge\", \"huge\"}\n};\n\nbuilder.Services\n    .AddHttpClient()\n    .AddMcpServer()\n    .WithStdioServerTransport()\n    .WithTool(\n        name: \"latex\",\n        title: \"LaTeX to Image\",\n        description:\n            \"\"\"\n            Converts LaTeX equations into markdown-formatted images for inline display.\n            Users can use #latex_setprefs tool to set preferences for dark mode and font size.\n            Available font sizes: tiny, small, large, LARGE, huge.\n            \"\"\",\n        tool: async (IHttpClientFactory httpFactory, IMcpServer server,\n            [Description(\"The LaTeX equation to render.\")] string latex)\n            =>\n        {\n            // On first tool run, we ask for preferences for dark mode and font size.\n            if (!initialized)\n            {\n                initialized = true;\n                (darkMode, fontSize) = await SetPreferences(server, darkMode, fontSize);\n            }\n\n            var colors = darkMode switch\n            {\n                true => @\"\\fg{white}\",\n                false => @\"\\fg{black}\",\n                null => @\"\\bg{white}\\fg{black}\"\n            };\n\n            var query = WebUtility.UrlEncode(@\"\\dpi{300}\\\" + (fontSize ?? \"small\") + colors + new string([.. latex.Where(c => !char.IsWhiteSpace(c))]));\n            var url = $\"https://latex.codecogs.com/png.image?{query}\";\n\n            using var client = httpFactory.CreateClient();\n            using var response = await client.GetAsync(url);\n            response.EnsureSuccessStatusCode();\n\n            var base64 = Convert.ToBase64String(await response.Content.ReadAsByteArrayAsync());\n            return $\"> ![LaTeX Equation](data:image/png;base64,{base64})\";\n        })\n    .WithTool(\n        name: \"latex_getprefs\",\n        title: \"Get LaTeX Preferences\",\n        description: \"Gets the saved LaTeX rendering preferences for dark mode and font size.\",\n        tool: () => new { darkMode, fontSize },\n        options: ToolJsonOptions.Default)\n    .WithTool(\n        name: \"latex_setprefs\",\n        title: \"Set LaTeX Preferences\",\n        description: \"Sets the LaTeX rendering preferences for dark mode and font size.\",\n        tool: async (IMcpServer server,\n            [Description(\"Use dark mode by inverting the colors in the output.\")] bool? darkMode = null,\n            [Description(\"Font size to use in the output: tiny=5pt, small=9pt, large=12pt, LARGE=18pt, huge=20pt\")] string? fontSize = null)\n            => (darkMode, fontSize) = await SetPreferences(server, darkMode, fontSize),\n        options: ToolJsonOptions.Default);\n\nawait builder.Build().RunAsync();\n\n/// <summary>Saves the LaTeX rendering preferences to configuration.</summary>\nasync ValueTask<(bool? darkMode, string? fontSize)> SetPreferences(IMcpServer server, bool? darkMode, string? fontSize)\n{\n    if ((darkMode is null || fontSize is null || !fonts.ContainsValue(fontSize)) && server.ClientCapabilities?.Elicitation != null)\n    {\n        var result = await server.ElicitAsync(new()\n        {\n            Message = \"Specify LaTeX rendering preferences\",\n            RequestedSchema = new()\n            {\n                Required = [\"darkMode\", \"fontSize\"],\n                Properties =\n                {\n                    { \"darkMode\",  new ElicitRequestParams.BooleanSchema()\n                        {\n                            Title = \"Dark Mode\",\n                            Description = \"Use dark mode?\",\n                            Default = darkMode\n                        }\n                    },\n                    { \"fontSize\",  new ElicitRequestParams.EnumSchema()\n                        {\n                            Title = \"Font Size\",\n                            Description = \"Font size to use for the LaTeX rendering.\",\n                            Enum = [.. fonts.Values],\n                            EnumNames = [.. fonts.Keys],\n                        }\n                    },\n                },\n            }\n        });\n\n        if (result.Action == \"accept\" && result.Content is { } content)\n        {\n            darkMode = content[\"darkMode\"].GetBoolean();\n            fontSize = content[\"fontSize\"].GetString() ?? \"tiny\";\n\n            DotNetConfig.Config.Build(DotNetConfig.ConfigLevel.Global)\n                .GetSection(\"latex\")\n                .SetBoolean(\"darkMode\", darkMode.Value)\n                .SetString(\"fontSize\", fontSize);\n        }\n        // action == cancel is not supported in vscode\n        // actoin == decline would be equal to \"ignore\" so we just don't set anything.\n        return (darkMode, fontSize);\n    }\n    else\n    {\n        // We persist to ~/.netconfig\n        var config = DotNetConfig.Config.Build(DotNetConfig.ConfigLevel.Global).GetSection(\"latex\");\n        if (darkMode != null)\n            config = config.SetBoolean(\"darkMode\", darkMode.Value);\n        if (fontSize != null && fonts.ContainsValue(fontSize))\n            config = config.SetString(\"fontSize\", fontSize);\n        else\n            fontSize = null;\n\n        return (darkMode, fontSize);\n    }\n}"
  },
  {
    "path": "src/Demo/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Humanizer.cs\": {\n      \"commandName\": \"Project\"\n    },\n    \"Mcp.cs\": {\n      \"commandName\": \"Project\"\n    },\n    \"Hello.cs\": {\n      \"commandName\": \"Project\"\n    }\n  }\n}"
  },
  {
    "path": "src/Demo/global.json",
    "content": "{\n  \"msbuild-sdks\": {\n    \"SmallSharp\": \"42.537.1166\"\n  }\n}\n"
  },
  {
    "path": "src/Demo/nuget.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <add key=\"nuget.org\" value=\"https://api.nuget.org/v3/index.json\" />\n    <add key=\"kzu\" value=\"https://pkg.kzu.app/index.json\" />\n    <add key=\"local\" value=\"../../bin/\" />\n  </packageSources>\n  <activePackageSource>\n    <add key=\"All\" value=\"(Aggregate source)\" />\n  </activePackageSource>\n  <packageSourceMapping>\n    <packageSource key=\"nuget.org\">\n      <package pattern=\"*\" />\n    </packageSource>\n    <packageSource key=\"kzu\">\n      <package pattern=\"SmallSharp\" />\n    </packageSource>\n    <packageSource key=\"local\">\n      <package pattern=\"SmallSharp\" />\n    </packageSource>\n  </packageSourceMapping>\n</configuration>\n"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project TreatAsLocalProperty=\"VersionPrefix\">\n  <!-- To extend/change the defaults, create a Directory.props alongside this file -->\n\n  <PropertyGroup Label=\"CI\" Condition=\"'$(CI)' == ''\">\n    <CI>false</CI>\n    <!-- GH, CircleCI, GitLab and BitBucket already use CI -->\n    <CI Condition=\"'$(TF_BUILD)' == 'true' or \n                   '$(TEAMCITY_VERSION)' != '' or \n                   '$(APPVEYOR)' != '' or \n                   '$(BuildRunner)' == 'MyGet' or \n                   '$(JENKINS_URL)' != '' or \n                   '$(TRAVIS)' == 'true' or \n                   '$(BUDDY)' == 'true'\">true</CI>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <!-- The Microsoft.Managed.Core.targets use this property to use deterministic source paths in CI builds -->\n    <ContinuousIntegrationBuild>$(CI)</ContinuousIntegrationBuild>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"NuGet\">\n    <Authors>Daniel Cazzulino</Authors>\n    <Company>Devlooped</Company>\n    <Copyright>Copyright (C) Daniel Cazzulino and Contributors. All rights reserved.</Copyright>\n    <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\n    <!-- Pick src-level readme+icon automatically -->\n    <PackageIcon Condition=\"Exists('$(MSBuildThisFileDirectory)icon.png')\">icon.png</PackageIcon>\n    <PackageReadmeFile Condition=\"'$(PackReadme)' != 'false' and Exists('$(MSBuildThisFileDirectory)readme.md')\">readme.md</PackageReadmeFile>\n    <!-- Pick project-level readme+icon overrides automatically -->\n    <PackageIcon Condition=\"Exists('$(MSBuildProjectDirectory)\\icon.png')\">icon.png</PackageIcon>\n    <PackageReadmeFile Condition=\"'$(PackReadme)' != 'false' and Exists('$(MSBuildProjectDirectory)\\readme.md')\">readme.md</PackageReadmeFile>\n\n    <PublishRepositoryUrl>true</PublishRepositoryUrl>\n    <GenerateRepositoryUrlAttribute>true</GenerateRepositoryUrlAttribute>\n\n    <PackageOutputPath Condition=\"'$(PackageOutputPath)' == ''\">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\\bin'))</PackageOutputPath>\n\n    <!-- Use Directory.Packages.props if possible. NOTE: other MSBuild SDKs (i.e. NoTargets/Traversal) do not support central packages -->\n    <ManagePackageVersionsCentrally Condition=\"Exists('$(MSBuildThisFileDirectory)Directory.Packages.props')\">true</ManagePackageVersionsCentrally>\n    <CentralPackageFloatingVersionsEnabled>true</CentralPackageFloatingVersionsEnabled>\n\n    <!-- Ensure MSBuild tooling can access package artifacts always via PKG_[PackageId] -->\n    <GeneratePathProperty>true</GeneratePathProperty>\n    <!-- Avoid warnings for test projects when we run dotnet pack on the whole solution. -->\n    <WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>\n    <!-- See https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#prunepackagereference-specification -->\n    <RestoreEnablePackagePruning>true</RestoreEnablePackagePruning>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Build\">\n    <Configuration Condition=\"'$(Configuration)' == '' and $(CI)\">Release</Configuration>\n    <LangVersion>Latest</LangVersion>\n\n    <!-- See https://docs.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies -->\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <!-- Because they are small and super useful and supported everywhere -->\n    <DebugType>embedded</DebugType>\n    <DebugSymbols>true</DebugSymbols>\n    <Nullable>enable</Nullable>\n    <!-- See https://www.meziantou.net/csharp-compiler-strict-mode.htm -->\n    <Features>strict</Features>\n    \n    <!-- Simplify namespaces by defaulting to the single root name -->\n    <RootNamespace>$(MSBuildProjectName)</RootNamespace>\n    <RootNamespaceDot>$(MSBuildProjectName.IndexOf('.'))</RootNamespaceDot>\n    <RootNamespace Condition=\"'$(RootNamespaceDot)' != '-1'\">$(MSBuildProjectName.Substring(0, $(RootNamespaceDot)))</RootNamespace>\n\n    <!-- We typically don't want these files shown in the solution explorer -->\n    <DefaultItemExcludes>$(DefaultItemExcludes);*.binlog;*.zip;*.rsp;*.items;**/TestResults/**/*.*</DefaultItemExcludes>\n\n    <EnableSourceLink>true</EnableSourceLink>\n    <EnableSourceControlManagerQueries>true</EnableSourceControlManagerQueries>\n    <EmbedUntrackedSources>true</EmbedUntrackedSources>\n    <UseSourceLink>true</UseSourceLink>\n\n    <!-- Generate satellite assemblies using csc.exe to avoid some al.exe issues. See https://github.com/dotnet/msbuild/pull/2726 -->\n    <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>\n\n    <!-- See: https://www.cazzulino.com/project-dependencies-as-project-references.html -->\n    <AddSyntheticProjectReferencesForSolutionDependencies>false</AddSyntheticProjectReferencesForSolutionDependencies>\n\n    <!-- Don't warn for packages using semver 2.0 -->\n    <NoWarn>NU5105;$(NoWarn)</NoWarn>\n    <!-- Turn warnings into errors in CI or Release builds -->\n    <WarningsAsErrors Condition=\"$(CI) or '$(Configuration)' == 'Release'\">true</WarningsAsErrors>\n    \n    <!-- Preserve transitively copied content in VS: https://github.com/dotnet/msbuild/issues/1054#issuecomment-847959047 -->\n    <MSBuildCopyContentTransitively>true</MSBuildCopyContentTransitively>\n    \n    <!-- Global tools should run on whatever latest runtime is installed. See https://docs.microsoft.com/en-us/dotnet/core/versions/selection#framework-dependent-apps-roll-forward -->\n    <RollForward>LatestMinor</RollForward>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"StrongName\" Condition=\"Exists('$(MSBuildThisFileDirectory)kzu.snk')\">\n    <!-- We use a single oss signing key for consumers that need strong-named assemblies -->\n    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)kzu.snk</AssemblyOriginatorKeyFile>\n    <!-- These properties make it easier to add internals visible to other projects, even when signing is involved.\n         For example, you can simply add: \n          <InternalsVisibleTo Include=\"MyProject.UnitTests\" />\n\n         and the key will be appended automatically.\n    -->\n    <PublicKey>002400000480000094000000060200000024000052534131000400000100010051155fd0ee280be78d81cc979423f1129ec5dd28edce9cd94fd679890639cad54c121ebdb606f8659659cd313d3b3db7fa41e2271158dd602bb0039a142717117fa1f63d93a2d288a1c2f920ec05c4858d344a45d48ebd31c1368ab783596b382b611d8c92f9c1b3d338296aa21b12f3bc9f34de87756100c172c52a24bad2db</PublicKey>\n    <PublicKeyToken>00352124762f2aa5</PublicKeyToken>\n    <SignAssembly>true</SignAssembly>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Version\">\n    <!-- Versioning: when building locally, it's always 42.42.42. \n         This makes it always bigger than any public package version, and \n         consistent and fixed for dogfooding. \n         NuGetizer nukes the package cache on build, making this straightforward too.\n         CI (non-release) builds pass in a VersionSuffix property to append a label \n         after the fixed prefix. This allows dogfooding a branch build.\n         The suffix is sanitized and optionally turned into \n    -->\n    <VersionPrefix Condition=\"$(VersionPrefix) == ''\">42.42.42</VersionPrefix>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Version\" Condition=\"$(VersionLabel) != ''\">\n    <_VersionLabel>$(VersionLabel.Replace('refs/heads/', ''))</_VersionLabel>\n    <_VersionLabel>$(_VersionLabel.Replace('refs/tags/v', ''))</_VersionLabel>\n\n    <!-- For PRs, we just need a fixed package version numbered after the PR # itself, so remove the commits # at the end -->\n    <_VersionLabel Condition=\"$(_VersionLabel.Contains('refs/pull/'))\">$(VersionLabel.TrimEnd('.0123456789'))</_VersionLabel>\n    <!-- Next replace the prefix for simply 'pr', so we end up with 'pr99/merge' by default -->\n    <_VersionLabel>$(_VersionLabel.Replace('refs/pull/', 'pr'))</_VersionLabel>\n    <!-- Remove the /merge now, if present -->\n    <_VersionLabel>$(_VersionLabel.Replace('/merge', ''))</_VersionLabel>\n    <!-- Finally sanitize the branch with dashes, so we can build path-separated branches, like rel/v1.0.0 or feature/foo -->\n    <_VersionLabel>$(_VersionLabel.Replace('/', '-'))</_VersionLabel>\n    <!-- And underscores which are also invalid labels, so we can use branches like dev/feature_foo -->\n    <_VersionLabel>$(_VersionLabel.Replace('_', '-'))</_VersionLabel>\n\n    <!-- Set sanitized version to the actual version suffix used in build/pack -->\n    <VersionSuffix Condition=\"!$(VersionLabel.Contains('refs/tags/'))\">$(_VersionLabel)</VersionSuffix>\n    <!-- Special case for tags, the label is actually the version. Backs compat since passed-in value overrides MSBuild-set one -->\n    <Version Condition=\"$(VersionLabel.Contains('refs/tags/'))\">$(_VersionLabel)</Version>\n\n    <!-- In order for latest from main/master to always be greatest when using -prerelease switch on install/run, \n         we change the scheme as follows:\n         - main/master remain as today: VersionPrefix: 42.42.${{ github.run_number }}  (from yaml)\n         - others: VersionPrefix: 42.42.0-[label].${{ github.run_number }}\n    -->\n    <IsMaster Condition=\"$(VersionLabel.Contains('refs/heads/main')) or $(VersionLabel.Contains('refs/heads/master'))\">true</IsMaster>\n    <VersionPrefix Condition=\"'$(IsMaster)' != 'true'\">42.42.0</VersionPrefix>\n    <VersionSuffix Condition=\"'$(IsMaster)' != 'true'\">$(VersionSuffix).$(GITHUB_RUN_NUMBER)</VersionSuffix>\n  </PropertyGroup>\n\n  <ItemGroup Label=\"ThisAssembly.Project\">\n    <ProjectProperty Include=\"CI\" />\n  \n    <ProjectProperty Include=\"Version\" />\n    <ProjectProperty Include=\"VersionPrefix\" />\n    <ProjectProperty Include=\"VersionSuffix\" />\n\n    <ProjectProperty Include=\"PublicKey\" />\n    <ProjectProperty Include=\"PublicKeyToken\" />\n  </ItemGroup>\n\n  <ItemGroup Label=\"Throw\">\n    <Using Include=\"System.ArgumentException\" Static=\"true\" />\n    <Using Include=\"System.ArgumentOutOfRangeException\" Static=\"true\" />\n    <Using Include=\"System.ArgumentNullException\" Static=\"true\" />\n  </ItemGroup>\n\n  <ItemGroup Label=\"OSMF\" Condition=\"Exists('$(MSBuildThisFileDirectory)..\\osmfeula.txt')\">\n    <Content Include=\"$(MSBuildThisFileDirectory)..\\osmfeula.txt\" Link=\"osmfeula.txt\" Pack=\"true\" PackagePath=\"OSMFEULA.txt\" />\n  </ItemGroup>\n\n  <Import Project=\"Directory.props\" Condition=\"Exists('Directory.props')\"/>\n  <Import Project=\"Directory.props.user\" Condition=\"Exists('Directory.props.user')\" />\n\n  <!-- If the imported props changed ManagePackageVersionsCentrally, we need to replicate \n       the Version defaults from Microsoft.NET.DefaultAssemblyInfo.targets since it's too \n       early here and Directory.Packages.props will be imported right after this time, \n       meaning dependencies that expect to use the currently building Version would not \n       get the expected value.\n   -->\n  <PropertyGroup Condition=\"'$(ManagePackageVersionsCentrally)' == 'true' and '$(Version)' == ''\">\n    <VersionPrefix Condition=\" '$(VersionPrefix)' == '' \">1.0.0</VersionPrefix>\n    <Version Condition=\" '$(VersionSuffix)' != '' \">$(VersionPrefix)-$(VersionSuffix)</Version>\n    <Version Condition=\" '$(Version)' == '' \">$(VersionPrefix)</Version>\n  </PropertyGroup>\n\n  <!-- Implemented by SDK in .targets, guaranteeing it's overwritten. Added here since we add a DependsOnTargets to it. \n       Covers backwards compatiblity with non-SDK projects. -->\n  <Target Name=\"InitializeSourceControlInformation\" />\n</Project>\n"
  },
  {
    "path": "src/Directory.Build.targets",
    "content": "<Project>\n  <!-- To extend/change the defaults, create a Directory.targets alongside this file -->\n\n  <PropertyGroup Condition=\"'$(CI)' == 'true' and '$(Language)' == 'C#'\">\n    <DefineConstants>CI;$(DefineConstants)</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Build\">\n    <!-- Tests projects don't need API docs, typically -->\n    <GenerateDocumentationFile Condition=\"$(GenerateDocumentationFile) == '' and $(IsTestProject) == 'true'\">false</GenerateDocumentationFile>\n    <GenerateDocumentationFile Condition=\"$(GenerateDocumentationFile) == '' and $(MSBuildProjectName.Contains('Tests'))\">false</GenerateDocumentationFile>\n    <GenerateDocumentationFile Condition=\"$(GenerateDocumentationFile) == ''\">true</GenerateDocumentationFile>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(IsPackable)' == ''\">\n    <IsPackable Condition=\"'$(PackAsTool)' == 'true'\">true</IsPackable>\n    <IsPackable Condition=\"'$(PackFolder)' != ''\">true</IsPackable>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(IsPackable)' == ''\">\n    <!-- The Sdks\\NuGet.Build.Tasks.Pack\\build\\NuGet.Build.Tasks.Pack.targets unconditionally sets \n        PackageId=AssemblyName if no PackageId is provided, and then defaults IsPackable=true if \n        a PackageId is set (?!), meaning that by default everything is packable in Sdk-style \n        projects. \n\n        The Directory.Build.targets are imported after the user's project properties have been \n        read, and therefore gives us a chance to inspect if an explicit PackageId was provided, \n        before the NuGet SDK target is imported and defaults it. At this point, we can give \n        IsPackable a more sensible default, making it false if no PackageId was provided at this \n        point. -->\n    <IsPackable Condition=\"'$(PackageId)' == ''\">false</IsPackable>\n    <IsPackable Condition=\"'$(PackageId)' != ''\">true</IsPackable>\n  </PropertyGroup>\n  \n  <ItemGroup Condition=\"'$(IsPackable)' == 'true'\" Label=\"NuGet\">\n    <!-- This is compatible with nugetizer and SDK pack -->\n    <!-- Only difference is we don't copy either to output directory -->\n\n    <!-- Project-level icon/readme will already be part of None items -->\n    <None Update=\"@(None -> WithMetadataValue('Filename', 'icon'))\" \n          Pack=\"true\" PackagePath=\"%(Filename)%(Extension)\" \n          CopyToOutputDirectory=\"Never\"\n          Condition=\"'$(PackageIcon)' != ''\" />\n\n    <None Update=\"@(None -> WithMetadataValue('Filename', 'readme'))\" \n          Pack=\"true\" PackagePath=\"%(Filename)%(Extension)\" \n          CopyToOutputDirectory=\"Never\"\n          Condition=\"'$(PackReadme)' != 'false' and '$(PackageReadmeFile)' != ''\" />\n    \n    <!-- src-level will need explicit inclusion -->\n    <None Include=\"$(MSBuildThisFileDirectory)icon.png\" Link=\"icon.png\" Visible=\"false\" \n          Pack=\"true\" PackagePath=\"%(Filename)%(Extension)\"\n          CopyToOutputDirectory=\"Never\"\n          Condition=\"Exists('$(MSBuildThisFileDirectory)icon.png') and !Exists('$(MSBuildProjectDirectory)\\icon.png')\" />\n\n    <None Include=\"$(MSBuildThisFileDirectory)readme.md\" Link=\"readme.md\"  \n          Pack=\"true\" PackagePath=\"%(Filename)%(Extension)\"\n          CopyToOutputDirectory=\"Never\"\n          Condition=\"'$(PackReadme)' != 'false' and Exists('$(MSBuildThisFileDirectory)readme.md') and !Exists('$(MSBuildProjectDirectory)\\readme.md')\" />\n  </ItemGroup>\n\n  <!-- Microsoft.NET.Sdk\\targets\\Microsoft.NET.DefaultAssemblyInfo.targets does this and is imported \n       before Directory.Build.targets, but it's not imported for .msbuildproj -->\n  <PropertyGroup Condition=\"'$(Version)' == ''\">\n    <VersionPrefix Condition=\"'$(VersionPrefix)' == ''\">1.0.0</VersionPrefix>\n    <Version Condition=\"'$(VersionSuffix)' != ''\">$(VersionPrefix)-$(VersionSuffix)</Version>\n    <Version Condition=\"'$(Version)' == ''\">$(VersionPrefix)</Version>\n  </PropertyGroup>\n\n  <!-- Append $(PackFolder) directory to output and intermediate paths to prevent bin clashes between targets. -->\n  <PropertyGroup Condition=\"'$(AppendPackFolderToOutputPath)' == 'true' and '$(PackFolder)' != ''\">\n    <PackFolderPath>$(PackFolder)</PackFolderPath>\n    <PackFolderPath Condition=\"'$(TargetFramework)' != ''\">$(PackFolderPath.Replace('\\$(TargetFramework)', ''))</PackFolderPath>\n    <IntermediateOutputPath>$(IntermediateOutputPath)$(PackFolderPath)\\</IntermediateOutputPath>\n    <OutputPath>$(OutputPath)$(PackFolderPath)\\</OutputPath>\n    <OutDir>$(OutputPath)</OutDir>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(RepositoryBranch)' == ''\">\n    <!-- GitHub Actions: https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != '' and $(GITHUB_REF.Contains('refs/pull/'))\">pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', ''))</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != ''\">$(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>\n    <!-- Azure DevOps: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(BUILD_SOURCEBRANCH)' != ''\">$(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>\n    <!-- AppVeyor: https://www.appveyor.com/docs/environment-variables/ -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(APPVEYOR_PULL_REQUEST_NUMBER)' != ''\">pr$(APPVEYOR_PULL_REQUEST_NUMBER)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_TAG_NAME)' != ''\">$(APPVEYOR_REPO_TAG_NAME)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_BRANCH)' != ''\">$(APPVEYOR_REPO_BRANCH)</RepositoryBranch>\n    <!-- TeamCity: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Branch-Related+Parameters -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(TEAMCITY_BUILD_BRANCH)' != ''\">$(TEAMCITY_BUILD_BRANCH)</RepositoryBranch>\n    <!--TravisCI: https://docs.travis-ci.com/user/environment-variables/ -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(TRAVIS_PULL_REQUEST)' != '' and '$(TRAVIS_PULL_REQUEST)' != 'false'\">pr$(TRAVIS_PULL_REQUEST)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(TRAVIS_BRANCH)' != ''\">$(TRAVIS_BRANCH)</RepositoryBranch>\n    <!-- CircleCI: https://circleci.com/docs/2.0/env-vars/ -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CIRCLE_PR_NUMBER)' != ''\">pr$(CIRCLE_PR_NUMBER)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CIRCLE_TAG)' != ''\">$(CIRCLE_TAG)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CIRCLE_BRANCH)' != ''\">$(CIRCLE_BRANCH)</RepositoryBranch>\n    <!-- GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CI_COMMIT_TAG)' != ''\">$(CI_COMMIT_TAG)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CI_MERGE_REQUEST_IID)' != ''\">pr$(CI_MERGE_REQUEST_IID)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CI_EXTERNAL_PULL_REQUEST_IID)' != ''\">pr$(CI_EXTERNAL_PULL_REQUEST_IID)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''\">$(CI_COMMIT_BRANCH)</RepositoryBranch>\n    <!-- Buddy: https://buddy.works/docs/pipelines/environment-variables#default-environment-variables -->\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''\">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''\">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>\n    <RepositoryBranch Condition=\"'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''\">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>\n  </PropertyGroup>  \n\n  <PropertyGroup>\n    <!-- Default to Just Works resources generation. See https://www.cazzulino.com/resources.html -->\n    <CoreCompileDependsOn>CoreResGen;$(CoreCompileDependsOn)</CoreCompileDependsOn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <!-- Consider the project out of date if any of these files changes -->\n    <UpToDateCheck Include=\"@(None);@(Content);@(EmbeddedResource)\" />\n    <!-- Opt-in to typed resource generation by setting custom tool to MSBuild:Compile -->\n    <EmbeddedResource Update=\"@(EmbeddedResource -> WithMetadataValue('Generator', 'MSBuild:Compile'))\" Type=\"Resx\">\n      <!-- Default to Just Works resources generation. See https://www.cazzulino.com/resources.html -->\n      <StronglyTypedFileName>$(IntermediateOutputPath)\\$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\\', '.').Replace('/', '.'))%(Filename).g$(DefaultLanguageSourceExtension)</StronglyTypedFileName>\n      <StronglyTypedLanguage>$(Language)</StronglyTypedLanguage>\n      <StronglyTypedNamespace Condition=\"'%(RelativeDir)' == ''\">$(RootNamespace)</StronglyTypedNamespace>\n      <StronglyTypedNamespace Condition=\"'%(RelativeDir)' != ''\">$(RootNamespace).$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\\', '.').Replace('/', '.').TrimEnd('.'))</StronglyTypedNamespace>\n      <StronglyTypedClassName>%(Filename)</StronglyTypedClassName>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <Target Name=\"IsPackable\" Returns=\"@(IsPackable)\">\n    <ItemGroup>\n      <IsPackable Include=\"$(MSBuildProjectFullPath)\" IsPackable=\"$(IsPackable)\" PackageId=\"$(PackageId)\" />\n    </ItemGroup>\n  </Target>\n\n  <ItemGroup>\n    <!-- Make these available via ThisAssembly.Project -->\n    <ProjectProperty Include=\"RepositoryBranch\" />\n    <ProjectProperty Include=\"RepositorySha\" />\n    <ProjectProperty Include=\"RepositoryCommit\" />\n    <ProjectProperty Include=\"RepositoryRoot\" />\n    <ProjectProperty Include=\"RepositoryUrl\" />\n  </ItemGroup>\n\n  <!-- Make sure the source control info is available before calling source generators -->\n  <Target Name=\"EnsureProjectInformation\" \n          BeforeTargets=\"GenerateMSBuildEditorConfigFileShouldRun\"\n          AfterTargets=\"InitializeSourceControlInformation\"\n          DependsOnTargets=\"InitializeSourceControlInformation\">\n    \n    <PropertyGroup Condition=\"'$(SourceControlInformationFeatureSupported)' == 'true'\">\n      <!-- The project must specify PublishRepositoryUrl=true in order to publish the URL, in order to prevent inadvertent leak of internal URL. -->\n      <RepositoryUrl Condition=\"'$(RepositoryUrl)' == '' and '$(PublishRepositoryUrl)' == 'true'\">$(PrivateRepositoryUrl)</RepositoryUrl>\n    </PropertyGroup>\n\n    <PropertyGroup Condition=\"'$(SourceRevisionId)' != ''\">\n      <RepositoryCommit Condition=\"'$(RepositoryCommit)' == ''\">$(SourceRevisionId)</RepositoryCommit>\n      <RepositorySha Condition=\"'$(RepositorySha)' == ''\">$(SourceRevisionId.Substring(0, 9))</RepositorySha>\n      <!-- This allows the commit label added to the InformationalVersion to be the short sha instead :) -->\n      <SourceRevisionId>$(RepositorySha)</SourceRevisionId>\n    </PropertyGroup>\n\n    <!-- Add SourceRoot as a project property too -->\n    <ItemGroup>\n      <_GitSourceRoot Include=\"@(SourceRoot -> WithMetadataValue('SourceControl', 'git'))\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <RepositoryRoot>@(_GitSourceRoot)</RepositoryRoot>\n      <!-- Only change if it wasn't just the default from Microsoft.NET.DefaultAssemblyInfo.targets -->\n      <ProductFromUrl Condition=\"'$(SourceControlInformationFeatureSupported)' == 'true'\">$([System.IO.Path]::GetFileNameWithoutExtension($(PrivateRepositoryUrl)))</ProductFromUrl>\n      <Product Condition=\"'$(Product)' == '$(AssemblyName)' and '$(ProductFromUrl)' != ''\">$(ProductFromUrl)</Product>\n    </PropertyGroup>\n\n  </Target>\n\n  <Target Name=\"UpdatePackageMetadata\"\n          BeforeTargets=\"PrepareForBuild;GenerateMSBuildEditorConfigFileShouldRun;GetAssemblyVersion;GetPackageMetadata;GenerateNuspec;Pack\"\n          DependsOnTargets=\"EnsureProjectInformation;UpdatePackageLicense\"\n          Condition=\"'$(SourceControlInformationFeatureSupported)' == 'true' And\n                     '$(IsPackable)' == 'true'\">\n    <PropertyGroup>\n      <PackageProjectUrl Condition=\"'$(PackageProjectUrl)' == '' and '$(PublishRepositoryUrl)' == 'true'\">$(RepositoryUrl.Replace('.git', ''))</PackageProjectUrl>\n      <PackageDescription>$(Description)</PackageDescription>\n      <PackageReleaseNotes Condition=\"'$(RepositoryUrl)' != '' and Exists('$(MSBuildThisFileDirectory)..\\changelog.md')\">$(RepositoryUrl.Replace('.git', ''))/blob/main/changelog.md</PackageReleaseNotes>\n    </PropertyGroup>\n  </Target>\n\n  <Target Name=\"UpdatePackageLicense\">\n    <!-- If project has a None/Content item with PackagePath=OSMFEULA.txt -->\n    <PropertyGroup Condition=\"@(None -> WithMetadataValue('PackagePath', 'OSMFEULA.txt')) != '' or @(Content -> WithMetadataValue('PackagePath', 'OSMFEULA.txt')) != ''\">\n      <PackageLicenseExpression></PackageLicenseExpression>\n      <PackageLicenseFile>OSMFEULA.txt</PackageLicenseFile>\n      <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    </PropertyGroup>\n  </Target>\n\n\n  <!-- Import before UsingTask because first to declare tasks wins -->\n  <Import Project=\"Directory.targets\" Condition=\"Exists('Directory.targets')\"/>\n  <Import Project=\"Directory.targets.user\" Condition=\"Exists('Directory.targets.user')\" />\n\n</Project>\n"
  },
  {
    "path": "src/Directory.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n    <PackOnBuild>true</PackOnBuild>\n    <PackageProjectUrl>https://clarius.org/SmallSharp</PackageProjectUrl>\n    <PublishRepositoryUrl>true</PublishRepositoryUrl>\n    <Product>SmallSharp</Product>\n    <NoWarn>NU1702;$(NoWarn)</NoWarn>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Directory.targets",
    "content": "<Project InitialTargets=\"SetLocalVersion\">\n\n  <Target Name=\"SetLocalVersion\" Condition=\"!$(CI)\">\n    <GetVersion>\n      <Output TaskParameter=\"Version\" PropertyName=\"Version\" />\n    </GetVersion>\n  </Target>\n\n  <UsingTask TaskName=\"GetVersion\" TaskFactory=\"RoslynCodeTaskFactory\" AssemblyFile=\"$(MSBuildToolsPath)\\Microsoft.Build.Tasks.Core.dll\">\n    <ParameterGroup>\n      <Version Output=\"true\" />\n    </ParameterGroup>\n    <Task>\n      <Using Namespace=\"System\" />\n      <Using Namespace=\"Microsoft.Build.Framework\"/>\n      <Code Type=\"Fragment\" Language=\"cs\">\n        <![CDATA[\n        var version = this.BuildEngine4.GetRegisteredTaskObject(\"Version\", RegisteredTaskObjectLifetime.Build);\n        if (version == null)\n        {\n            var epoc = DateTime.Parse(\"2024-03-15\");\n            var days = Math.Truncate(DateTime.UtcNow.Subtract(epoc).TotalDays);\n            var time = Math.Floor(DateTime.UtcNow.TimeOfDay.TotalMinutes);\n            version = \"42.\" + days + \".\" + time;\n            this.BuildEngine4.RegisterTaskObject(\"Version\", version, RegisteredTaskObjectLifetime.Build, false);\n        }\n        Version = (string)version;\n        ]]>\n      </Code>\n    </Task>\n  </UsingTask>\n\n</Project>"
  },
  {
    "path": "src/SmallSharp/ConsoleEncodingInitializer.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace System;\n\n/// <summary>\n/// Ensures that when running from Visual Studio on Windows, the console encoding is set to UTF-8 \n/// to support full Unicode and emoji output.\n/// </summary>\nclass ConsoleEncodingInitializer\n{\n#pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries\n    [ModuleInitializer]\n#pragma warning restore CA2255 // The 'ModuleInitializer' attribute should not be used in libraries\n    public static void Init()\n    {\n\n#if DEBUG\n        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n            Console.InputEncoding = Console.OutputEncoding = Encoding.UTF8;\n#endif\n    }\n}\n"
  },
  {
    "path": "src/SmallSharp/EmitTargets.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing System.Xml;\nusing System.Xml.Linq;\nusing Microsoft.Build.Framework;\nusing Microsoft.Build.Utilities;\nusing static SmallSharp.TaskItemFactory;\n\nnamespace SmallSharp;\n\npublic class EmitTargets : Task\n{\n    static readonly Regex sdkExpr = new(@\"^#:sdk\\s+(?<sdk>[^@]+?)(@(?<version>.+))?$\");\n    static readonly Regex packageExpr = new(@\"^#:package\\s+(?<id>[^@]+)@(?<version>.+)$\");\n    static readonly Regex propertyExpr = new(@\"^#:property\\s+(?<name>[^=]+)=(?<value>.+)$\");\n\n    [Required]\n    public required ITaskItem StartupFile { get; set; }\n\n    [Required]\n    public required string BaseIntermediateOutputPath { get; set; }\n\n    [Required]\n    public required string PropsFile { get; set; }\n\n    [Required]\n    public required string TargetsFile { get; set; }\n\n    [Required]\n    public required bool UsingSDK { get; set; }\n\n    public ITaskItem[] PackageReferences { get; set; } = [];\n\n    [Output]\n    public ITaskItem[] Packages { get; set; } = [];\n\n    [Output]\n    public ITaskItem[] Sdks { get; set; } = [];\n\n    [Output]\n    public ITaskItem[] Properties { get; set; } = [];\n\n    [Output]\n    public bool RestoreNeeded { get; set; } = false;\n\n    public override bool Execute()\n    {\n        if (StartupFile is null)\n            return false;\n\n        var packages = new List<ITaskItem>();\n        var sdkItems = new List<ITaskItem>();\n        var propItems = new List<ITaskItem>();\n\n        var filePath = StartupFile.GetMetadata(\"FullPath\");\n        var contents = File.ReadAllLines(filePath);\n\n        var items = new List<XElement>();\n        var properties = new List<XElement>();\n        var sdks = new List<XAttribute[]>();\n\n        foreach (var line in contents)\n        {\n            if (packageExpr.Match(line) is { Success: true } match)\n            {\n                var id = match.Groups[\"id\"].Value.Trim();\n                var version = match.Groups[\"version\"].Value.Trim();\n\n                packages.Add(NewTaskItem(id, [(\"Version\", version)]));\n\n                items.Add(new XElement(\"PackageReference\",\n                    new XAttribute(\"Include\", id),\n                    new XAttribute(\"Version\", version)));\n            }\n            else if (sdkExpr.Match(line) is { Success: true } sdkMatch)\n            {\n                var name = sdkMatch.Groups[\"sdk\"].Value.Trim();\n                var version = sdkMatch.Groups[\"version\"].Value.Trim();\n                if (!string.IsNullOrEmpty(version))\n                {\n                    sdkItems.Add(NewTaskItem(name, [(\"Version\", version)]));\n                    sdks.Add([new XAttribute(\"Sdk\", name), new XAttribute(\"Version\", version)]);\n                }\n                else\n                {\n                    sdkItems.Add(new TaskItem(name));\n                    sdks.Add([new XAttribute(\"Sdk\", name)]);\n                }\n            }\n            else if (propertyExpr.Match(line) is { Success: true } propMatch)\n            {\n                var name = propMatch.Groups[\"name\"].Value.Trim();\n                var value = propMatch.Groups[\"value\"].Value.Trim();\n\n                propItems.Add(NewTaskItem(name, [(\"Value\", value)]));\n                properties.Add(new XElement(name, value));\n            }\n        }\n\n        Packages = [.. packages];\n        Sdks = [.. sdkItems];\n        Properties = [.. propItems];\n\n        // We only emit the default SDK if the SmallSharpSDK is in use, since otherwise the \n        // project file is expected to define its own SDK and we'd be duplicating it.\n        if (sdks.Count == 0)\n            sdks.Add([new XAttribute(\"Sdk\", \"Microsoft.NET.Sdk\")]);\n\n        WriteXml(TargetsFile, new XElement(\"Project\",\n            new XElement(\"PropertyGroup\", properties),\n            // We emit the package references always, even if UsingSDK is true, because \n            // this works better with the background restore that VS does, and nuget \n            // deduplicates package references anyway.\n            new XElement(\"ItemGroup\", items)\n        ));\n\n        WriteXml(Path.Combine(BaseIntermediateOutputPath, \"SmallSharp.sdk.props\"), new XElement(\"Project\",\n            sdks.Select(x => new XElement(\"Import\", [new XAttribute(\"Project\", \"Sdk.props\"), .. x]))));\n\n        WriteXml(Path.Combine(BaseIntermediateOutputPath, \"SmallSharp.sdk.targets\"), new XElement(\"Project\",\n            sdks.Select(x => new XElement(\"Import\", [new XAttribute(\"Project\", \"Sdk.targets\"), .. x]))));\n\n        // We emit properties both to .props and .targets to ensure all values \n        // are strictly what's set in the script, either before or after .NET SDK reads them.\n        WriteXml(PropsFile, new XElement(\"Project\",\n            new XElement(\"PropertyGroup\", properties),\n            new XElement(\"PropertyGroup\",\n                [new XElement(\"SmallSharpProjectExtensionPropsImported\", \"true\")])));\n\n        // Determine if a restore is needed: if any discovered #:package (id+version) is not already\n        // present in the incoming PackageReferences list.\n        foreach (var pkg in packages)\n        {\n            var id = pkg.ItemSpec;\n            var version = pkg.GetMetadata(\"Version\");\n            var exists = PackageReferences?.Any(r =>\n                string.Equals(r.ItemSpec, id, StringComparison.OrdinalIgnoreCase) &&\n                string.Equals(r.GetMetadata(\"Version\"), version, StringComparison.OrdinalIgnoreCase)) == true;\n\n            if (!exists)\n            {\n                RestoreNeeded = true;\n                break;\n            }\n        }\n\n        return true;\n    }\n\n    void WriteXml(string path, XElement root)\n    {\n        if (Path.GetDirectoryName(path) is { } dir)\n            Directory.CreateDirectory(dir);\n\n        using var writer = XmlWriter.Create(path, new XmlWriterSettings { Indent = true });\n        root.Save(writer);\n    }\n}\n"
  },
  {
    "path": "src/SmallSharp/Sdk.Empty.props",
    "content": "<Project>\n  <!-- This is needed since the Microsoft.NET.SDK Sdk.props imports the Microsoft.Common.props unconditionally -->\n</Project>"
  },
  {
    "path": "src/SmallSharp/Sdk.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <ImportProjectExtensionProps>true</ImportProjectExtensionProps>\n    <ImportProjectExtensionTargets>true</ImportProjectExtensionTargets>\n    \n    <!-- Since we use this to build StartupFile list and as an SDK, we might not have .NET SDK imported yet (i.e. no C# files at all) -->\n    <UsingSmallSharpSDK>true</UsingSmallSharpSDK>\n\n    <!-- Workaround https://github.com/dotnet/sdk/issues/50573 -->\n    <AlternateCommonProps>$(MSBuildThisFileDirectory)\\Sdk.Empty.props</AlternateCommonProps>\n\n    <!-- Since we emit duplicate package references from SDK as well as .props -->\n    <NoWarn>$(NoWarn);NU1504</NoWarn>\n  </PropertyGroup>\n\n  <!-- Import Common.props explicitly we're too early here to use MSBuildProjectExtensionsPath -->\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"'$(MicrosoftCommonPropsHasBeenImported)' != 'true' and Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  \n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.NET.Sdk\"\n       Condition=\"!Exists('$(MSBuildProjectExtensionsPath)SmallSharp.sdks.props')\" />\n\n  <Import Project=\"$(MSBuildProjectExtensionsPath)SmallSharp.sdks.props\" \n       Condition=\"Exists('$(MSBuildProjectExtensionsPath)SmallSharp.sdks.props')\" />\n\n  <Import Project=\"..\\build\\SmallSharp.props\" />\n\n  <!-- In SDK mode, we don't get the content files like we do in package mode, so we add it explicitly here -->\n  <ItemGroup>\n    <Compile Include=\"$(MSBuildThisFileDirectory)..\\contentFiles\\cs\\netstandard2.0\\ConsoleEncodingInitializer.cs\" \n             NuGetPackageId=\"SmallSharp\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/SmallSharp/Sdk.targets",
    "content": "<Project>\n\n  <Import Project=\"Sdk.targets\" Sdk=\"Microsoft.NET.Sdk\"\n       Condition=\"!Exists('$(MSBuildProjectExtensionsPath)SmallSharp.sdks.targets')\" />\n\n  <Import Project=\"$(MSBuildProjectExtensionsPath)SmallSharp.sdks.targets\"\n       Condition=\"Exists('$(MSBuildProjectExtensionsPath)SmallSharp.sdks.targets')\" />\n\n  <Import Project=\"..\\build\\SmallSharp.targets\" />\n\n  <Target Name=\"ImplicitPackageReferenceFromStartupFile\" \n          BeforeTargets=\"_GenerateProjectRestoreGraphPerFramework;ResolvePackageAssets;CompileDesignTime;CollectUpToDateCheckInputDesignTime;CollectPackageReferences\"\n          DependsOnTargets=\"StartupFile\"\n          Condition=\"'$(StartupFile)' != '' and Exists('$(StartupFile)')\">\n\n    <!-- Optimize for restore success on first run without previously running our targets -->\n    <ReadLinesFromFile File=\"$(StartupFile)\">\n      <Output TaskParameter=\"Lines\" ItemName=\"_StartupFileLines\" />\n    </ReadLinesFromFile>\n\n    <ItemGroup>\n      <_PkgLines Include=\"@(_StartupFileLines)\"\n                 Condition=\"$([MSBuild]::ValueOrDefault('%(Identity)', '').StartsWith('#:package '))\" />\n    </ItemGroup>\n\n    <ItemGroup Condition=\"'@(_PkgLines)' != ''\">\n      <_PkgReference Include=\"$([MSBuild]::ValueOrDefault('%(_PkgLines.Identity)', '').Substring(10))\" />\n\n      <PackageReference Condition=\"'@(_PkgReference)' != ''\" Include=\"$([MSBuild]::ValueOrDefault('%(_PkgReference.Identity)', '').Split('@')[0])\">\n        <Version>$([MSBuild]::ValueOrDefault('%(_PkgReference.Identity)', '').Split('@')[1])</Version>\n      </PackageReference>\n    </ItemGroup>\n\n  </Target>\n\n</Project>"
  },
  {
    "path": "src/SmallSharp/SmallSharp.Before.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <_ImportProjectExtensionProps>$(ImportProjectExtensionProps)</_ImportProjectExtensionProps>\n    <_ImportProjectExtensionTargets>$(ImportProjectExtensionTargets)</_ImportProjectExtensionTargets>\n  </PropertyGroup>\n\n</Project>"
  },
  {
    "path": "src/SmallSharp/SmallSharp.Version.props",
    "content": "<Project>\n  <PropertyGroup>\n    <SmallSharpVersion>42.42.42</SmallSharpVersion>\n  </PropertyGroup>  \n</Project>"
  },
  {
    "path": "src/SmallSharp/SmallSharp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <PackageId>SmallSharp</PackageId>\n    <Description>\n      Create, edit and run multiple C# top-level programs in the same project in the IDE, \n      respecting per-file `#:package` references and `#:property` project values 😍\n    </Description>\n    <PackFolder>build</PackFolder>\n    <PackNone>true</PackNone>\n    <GenerateDocumentationFile>false</GenerateDocumentationFile>\n    <DevelopmentDependency>true</DevelopmentDependency>\n    <StartAction>Program</StartAction>\n    <StartProgram>$(VsInstallRoot)\\Common7\\IDE\\devenv.exe</StartProgram>\n    <PackageLicenseExpression></PackageLicenseExpression>\n    <PackageLicenseFile>OSMFEULA.txt</PackageLicenseFile>\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageTags>dotnet csharp run</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\osmfeula.txt\" Link=\"osmfeula.txt\" PackagePath=\"OSMFEULA.txt\" />\n    <Compile Update=\"ConsoleEncodingInitializer.cs\" Pack=\"true\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Build.Tasks.Core\" Version=\"17.13.26\" Pack=\"false\" />\n    <PackageReference Include=\"NuGetizer\" Version=\"1.4.7\" />\n    <PackageReference Include=\"JsonPoke\" Version=\"1.2.0\" Pack=\"false\" GeneratePathProperty=\"true\" />\n    <PackageReference Include=\"NuGet.Versioning\" Version=\"6.14.0\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"PolySharp\" Version=\"1.15.0\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"ThisAssembly.Project\" Version=\"2.1.2\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\_._\" PackFolder=\"lib\\netstandard2.0\" Visible=\"false\" />\n    <None Update=\"SmallSharp.props\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Update=\"SmallSharp.Version.props\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Update=\"SmallSharp.targets\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Update=\"SmallSharp.Before.targets\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Update=\"Sdk.*\" PackFolder=\"Sdk\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"$(PkgJsonPoke)\\build\\JsonPoke.dll\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" Visible=\"false\" />\n    <None Include=\"$(PkgJsonPoke)\\build\\Newtonsoft.Json.dll\" PackFolder=\"$(PackFolder)\" CopyToOutputDirectory=\"PreserveNewest\" Visible=\"false\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <UpToDateCheckInput Include=\"SmallSharp.targets;SmallSharp.Before.targets;Sdk.props;Sdk.Empty.props;Sdk.targets\" />\n    <ProjectProperty Include=\"PackageVersion\" />\n  </ItemGroup>\n\n  <Target Name=\"UpdatePackagingVersion\" BeforeTargets=\"Pack\">\n    <!-- Update packaging version targets -->\n    <XmlPoke XmlInputPath=\"$(OutputPath)SmallSharp.Version.props\" Query=\"/Project/PropertyGroup/SmallSharpVersion\" Value=\"$(Version)\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "src/SmallSharp/SmallSharp.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <!-- This disables compilation error in VS for #: prefix -->\n    <Features>$(Features);FileBasedProgram</Features>\n\n    <!-- Capture project-level properties before they are defaulted by Microsoft.Common.targets -->\n    <CustomBeforeMicrosoftCSharpTargets>$(MSBuildThisFileDirectory)\\SmallSharp.Before.props</CustomBeforeMicrosoftCSharpTargets>\n\n    <UsingSmallSharpSDK Condition=\"'$(UsingSmallSharpSDK)' == ''\">false</UsingSmallSharpSDK>    \n  </PropertyGroup>\n\n  <Import Project=\"SmallSharp.Version.props\"/>\n\n</Project>"
  },
  {
    "path": "src/SmallSharp/SmallSharp.targets",
    "content": "<Project>\n\n  <UsingTask AssemblyFile=\"SmallSharp.dll\" TaskName=\"EmitTargets\" />\n  <UsingTask AssemblyFile=\"JsonPoke.dll\" TaskName=\"JsonPoke\"/>\n\n  <PropertyGroup>\n    <UserProjectNamespace>\n      <Namespace Prefix=\"msb\" Uri=\"http://schemas.microsoft.com/developer/msbuild/2003\" />\n    </UserProjectNamespace>\n    <!-- Backs compat -->\n    <ActiveFile Condition=\"'$(ActiveCompile)' != ''\">$(ActiveCompile)</ActiveFile>\n    <StartupFile>$(ActiveFile)</StartupFile>\n    <StartupFile Condition=\"'$(StartupFile)' == ''\">$(Start)</StartupFile>\n    <StartupFile Condition=\"'$(StartupFile)' == ''\">$(S)</StartupFile>\n    <StartupFile Condition=\"'$(StartupFile)' == ''\">$(ActiveDebugProfile)</StartupFile>\n    <FindStartupFile Condition=\"'$(StartupFile)' == '' or !Exists('$(StartupFile)')\">true</FindStartupFile>\n    <StartupFileDependsOn>EnsureProperties;CollectStartupFile;ResolveStartupFile;SelectStartupFile;SelectTopLevelCompile;UpdateLaunchSettings;EmitTargets</StartupFileDependsOn>\n    \n    <!-- For CLI dotnet run, users must set ImportProjectExtensionProps/ImportProjectExtensionTargets=true -->\n    <SmallSharpPackagesProps>$(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).smallsharp.props</SmallSharpPackagesProps>\n    <SmallSharpPackagesTargets>$(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).smallsharp.targets</SmallSharpPackagesTargets>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <!-- Ensures all top-level files show up in the IDE -->\n    <None Include=\"*.cs\" Exclude=\"$(ActiveDebugProfile);$(ActiveFile)\" />\n    <Compile Remove=\"*.cs\" />\n\n    <!-- Ensure changes we make to this file trigger a new DTB -->\n    <UpToDateCheckBuilt Include=\"Properties\\launchSettings.json\" />\n    <UpToDateCheckBuilt Include=\"$(SmallSharpPackagesProps);$(SmallSharpPackagesTargets)\" />\n    <Compile Update=\"@(Compile -> WithMetadataValue('NuGetPackageId', 'SmallSharp'))\" Visible=\"false\" />\n\n    <!-- Include linked compile files too -->\n    <_LinkedCompile Include=\"@(Compile -> HasMetadata('Link'))\" />\n    <_NuGetLinked Include=\"@(_LinkedCompile -> HasMetadata('NuGetPackageId'))\" />\n    <_NoNuGetLinked Include=\"@(_LinkedCompile)\" Exclude=\"@(_NuGetLinked)\" />\n    <LinkedCompile Include=\"@(_NoNuGetLinked -> WithoutMetadataValue('Visible', 'false'))\" />\n    <Compile Remove=\"@(LinkedCompile -> WithoutMetadataValue('Link', '$(ActiveDebugProfile)'))\" />\n    <None Include=\"@(LinkedCompile -> WithoutMetadataValue('Link', '$(ActiveFile)'))\" />\n  </ItemGroup>\n\n  <!-- When restoring, if we include the source files, we'd get duplicate references. -->\n  <ItemGroup Condition=\"'$(MSBuildIsRestoring)' != 'true'\">\n    <Compile Include=\"$(ActiveDebugProfile)\" Condition=\"Exists('$(ActiveDebugProfile)')\" />\n    <Compile Include=\"$(ActiveFile)\" Condition=\"Exists('$(ActiveFile)') and '$(ActiveFile)' != '$(ActiveDebugProfile)'\" />\n  </ItemGroup>\n\n  <Target Name=\"StartupFile\" BeforeTargets=\"ResolvePackageAssets;CompileDesignTime;CollectUpToDateCheckInputDesignTime\" DependsOnTargets=\"$(StartupFileDependsOn)\" />\n\n  <Target Name=\"EnsureProperties\" Condition=\"'$(CheckSmallSharpRequirements)' != 'false'\">\n    <Error Code=\"SCS02\" Condition=\"'$(_ImportProjectExtensionProps)' != 'true' or '$(_ImportProjectExtensionTargets)' != 'true'\"\n           Text=\"Setting ImportProjectExtensionProps and ImportProjectExtensionTargets project properties to 'true' is required by SmallSharp to support C# package and project directives.\" />\n    <Error Code=\"SCS03\" Condition=\"'$(ManagePackageVersionsCentrally)' == 'true'\" \n           Text=\"Setting ManagePackageVersionsCentrally to 'true' is not supported by SmallSharp since C# program files can declare package references via #:package directives.\" />\n    <Warning Code=\"SCS04\" Condition=\"'$(UsingSmallSharpSDK)' != 'true'\"\n             Text='For maximum compatibility with file-based apps, use SmallSharp as an SDK instead of a package reference: &lt;Project Sdk=\"SmallSharp/$(SmallSharpVersion)\"&gt;' />\n  </Target>\n\n  <Target Name=\"CollectStartupFile\">\n    <ItemGroup>\n      <StartupFile Include=\"*.cs\" />\n      <StartupFile Include=\"@(LinkedCompile)\" />\n    </ItemGroup>\n  </Target>\n\n  <Target Name=\"ResolveStartupFile\" Condition=\"'$(FindStartupFile)' == 'true'\">\n    <ItemGroup>\n      <!-- Find if the specified StartupFile is a filename that matches an available StartupFile item -->\n      <_MatchingStartupFile Include=\"@(StartupFile)\" Condition=\"'$(StartupFile)' != '' and '%(Filename)%(Extension)' == '$(StartupFile)'\" />\n    </ItemGroup>\n    <PropertyGroup Condition=\"'@(_MatchingStartupFile)' != ''\">\n      <StartupFile>@(_MatchingStartupFile -> '%(Identity)')</StartupFile>\n      <FindStartupFile>false</FindStartupFile>\n    </PropertyGroup>\n  </Target>\n\n  <!-- Defaults the startup file to the first Compile, if none previously selected. -->\n  <Target Name=\"SelectStartupFile\" Condition=\"'$(FindStartupFile)' == 'true'\" Returns=\"$(StartupFile)\">\n\n    <ItemGroup>\n      <ReversedCompile Include=\"@(StartupFile -> Reverse())\" />\n    </ItemGroup>\n    <PropertyGroup>\n      <StartupFile>%(ReversedCompile.Identity)</StartupFile>\n    </PropertyGroup>\n\n    <!-- If .user file doesn't exist at all, create it now -->\n    <PropertyGroup Condition=\"!Exists('$(MSBuildProjectFullPath).user')\">\n      <UserProject>\n        <Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n          <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n            <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>\n          </PropertyGroup>\n          <PropertyGroup>\n            <ActiveDebugProfile>$(StartupFile)</ActiveDebugProfile>\n          </PropertyGroup>\n        </Project>\n      </UserProject>\n      <WriteStartupFile>false</WriteStartupFile>\n    </PropertyGroup>\n    <WriteLinesToFile File=\"$(MSBuildProjectFullPath).user\"\n                      Lines=\"$(UserProject)\"\n                      Condition=\"!Exists('$(MSBuildProjectFullPath).user')\" />\n\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Value=\"$(StartupFile)\"\n             Query=\"/msb:Project/msb:PropertyGroup/msb:ActiveDebugProfile\"\n             Namespaces=\"$(UserProjectNamespace)\"\n             Condition=\"'$(WriteStartupFile)' != 'false' and '$(StartupFile)' != ''\"/>\n\n    <XmlPeek XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Query=\"/msb:Project/msb:PropertyGroup/msb:ActiveDebugProfile/text()\"\n             Namespaces=\"$(UserProjectNamespace)\">\n      <Output TaskParameter=\"Result\" PropertyName=\"StartupDebugProfile\" />\n    </XmlPeek>\n\n    <PropertyGroup Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\">\n      <ActiveDebugProfileProperty>\n        <ActiveDebugProfile>$(StartupFile)</ActiveDebugProfile>\n      </ActiveDebugProfileProperty>\n    </PropertyGroup>\n\n    <!-- The ActiveDebugProfile property element may be missing, failing to write the value -->\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Value=\"$(ActiveDebugProfileProperty)\"\n             Query=\"/msb:Project/msb:PropertyGroup\"\n             Namespaces=\"$(UserProjectNamespace)\"\n             Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\"/>\n\n    <!-- Read again after we poke the ActiveDebugProfile property -->\n    <XmlPeek XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Query=\"/msb:Project/msb:PropertyGroup/msb:ActiveDebugProfile/text()\"\n             Namespaces=\"$(UserProjectNamespace)\">\n      <Output TaskParameter=\"Result\" PropertyName=\"StartupDebugProfile\" />\n    </XmlPeek>\n\n    <!-- The entire PropertyGroup could have been missing, failing to write the value -->\n    <PropertyGroup Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\">\n      <UserPropertyGroup>\n        <PropertyGroup>\n          <ActiveDebugProfile>$(StartupFile)</ActiveDebugProfile>\n        </PropertyGroup>\n      </UserPropertyGroup>\n    </PropertyGroup>\n\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Value=\"$(UserPropertyGroup)\"\n             Query=\"/msb:Project\"\n             Namespaces=\"$(UserProjectNamespace)\"\n             Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\"/>\n\n    <!-- Read again after we poke the PropertyGroup -->\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath).user\"\n             Value=\"$(StartupFile)\"\n             Query=\"/msb:Project/msb:PropertyGroup/msb:ActiveDebugProfile\"\n             Namespaces=\"$(UserProjectNamespace)\"\n             Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\"/>\n\n    <Warning Text=\"Could not set ActiveDebugProfile=$(StartupFile). Run the project once to fix it.\"\n             Condition=\"'$(StartupFile)' != '' and '$(StartupDebugProfile)' != '$(StartupFile)'\"/>\n\n  </Target>\n\n  <Target Name=\"SelectTopLevelCompile\">\n    <ItemGroup>\n      <!-- We remove all top-level from Compile because copy/pasting startup files may end up \n           causing those items to be hardcoded in the .csproj -->\n      <Compile Remove=\"@(Compile -> WithMetadataValue('RelativeDir', ''))\" />\n      <!-- Remove linked compile files too -->\n      <Compile Remove=\"@(Compile -> HasMetadata('Link'))\" />\n      <Compile Include=\"$(StartupFile)\" Condition=\"'$(StartupFile)' != '' and Exists('$(StartupFile)')\" />\n      <UpToDateCheckInput Include=\"$(StartupFile)\" Condition=\"'$(StartupFile)' != '' and Exists('$(StartupFile)')\" />\n    </ItemGroup>\n  </Target>\n\n  <Target Name=\"AfterClean\">\n    <Delete Files=\"$(MSBuildProjectDirectory)\\Properties\\launchSettings.json\"\n            Condition=\"Exists('$(MSBuildProjectDirectory)\\Properties\\launchSettings.json')\" />\n  </Target>\n\n  <Target Name=\"UpdateLaunchSettings\">\n    <WriteLinesToFile File=\"$(MSBuildProjectDirectory)\\Properties\\launchSettings.json\"\n                      Lines=\"{ }\"\n                      Condition=\"!Exists('$(MSBuildProjectDirectory)\\Properties\\launchSettings.json')\" />\n    <SortItems Items=\"@(StartupFile)\">\n      <Output TaskParameter=\"SortedItems\" ItemName=\"SortedStartupFile\" />\n    </SortItems>\n    <JsonPoke ContentPath=\"$(MSBuildProjectDirectory)\\Properties\\launchSettings.json\"\n              Query=\"$.profiles['%(SortedStartupFile.Filename)%(SortedStartupFile.Extension)'].commandName\"\n              Value=\"Project\" />\n  </Target>\n\n  <Target Name=\"EmitTargets\" DependsOnTargets=\"CollectStartupFile;SelectTopLevelCompile;SelectStartupFile\" \n          Inputs=\"@(Compile);$(ActiveDebugProfile);$(ActiveFile);Properties\\launchSettings.json\" \n          Outputs=\"$(SmallSharpPackagesProps);$(SmallSharpPackagesTargets)\">\n    <EmitTargets StartupFile=\"$(StartupFile)\" \n                 UsingSDK=\"$(UsingSmallSharpSDK)\"\n                 PackageReferences=\"@(PackageReferences)\"\n                 PropsFile=\"$(SmallSharpPackagesProps)\"\n                 TargetsFile=\"$(SmallSharpPackagesTargets)\"\n                 BaseIntermediateOutputPath=\"$(BaseIntermediateOutputPath)\">\n      <Output TaskParameter=\"Packages\" ItemName=\"FileBasedPackage\" />\n      <Output TaskParameter=\"Properties\" PropertyName=\"FileBasedProperty\" />\n      <Output TaskParameter=\"Sdks\" PropertyName=\"FileBasedSdk\" />\n      <Output TaskParameter=\"RestoreNeeded\" PropertyName=\"RestoreNeeded\" />\n    </EmitTargets>\n    <Error Code=\"SCS001\" Condition=\"'@(FileBasedSdk)' != '' and '$(UsingSmallSharpSDK)' != 'true'\"\n           Text=\"Using #:sdk directives requires using SmallSharp as an SDK instead of a package reference: &lt;Project Sdk='SmallSharp/$(SmallSharpVersion)'&gt;\" />\n  </Target>\n\n  <UsingTask TaskName=\"SortItems\" TaskFactory=\"RoslynCodeTaskFactory\" AssemblyFile=\"$(MSBuildToolsPath)\\Microsoft.Build.Tasks.Core.dll\">\n    <ParameterGroup>\n      <!-- ITaskItem[] input and sorted output -->\n      <Items ParameterType=\"Microsoft.Build.Framework.ITaskItem[]\" Required=\"true\" />\n      <SortedItems ParameterType=\"Microsoft.Build.Framework.ITaskItem[]\" Output=\"true\" />\n    </ParameterGroup>\n    <Task>\n      <Using Namespace=\"System\" />\n      <Code Type=\"Fragment\" Language=\"cs\">\n        <![CDATA[\n        SortedItems = Items.OrderBy(i => i.ItemSpec).ToArray();\n        ]]>\n      </Code>\n    </Task>\n  </UsingTask>\n\n  <UsingTask TaskName=\"DumpItems\" TaskFactory=\"RoslynCodeTaskFactory\" AssemblyFile=\"$(MSBuildToolsPath)\\Microsoft.Build.Tasks.Core.dll\">\n    <ParameterGroup>\n      <Items ParameterType=\"Microsoft.Build.Framework.ITaskItem[]\" Required=\"true\" />\n      <ItemName />\n    </ParameterGroup>\n    <Task>\n      <Using Namespace=\"Microsoft.Build.Framework\" />\n      <Using Namespace=\"Microsoft.Build.Utilities\" />\n      <Using Namespace=\"System\" />\n      <Using Namespace=\"System.Linq\" />\n      <Code Type=\"Fragment\" Language=\"cs\">\n        <![CDATA[\n\t\t\t  var itemName = ItemName ?? \"Item\";\n\t\t\t  if (Items.Length == 0)\n\t\t\t\t  Log.LogMessage(MessageImportance.High, \"No {0} items received to dump.\", ItemName ?? \"\");\n\t\t\t  else\n\t\t\t\t  Log.LogMessage(MessageImportance.High, \"Dumping {0} {1} items.\", Items.Length, ItemName ?? \"\");\n\n\t\t\t  foreach (var item in Items.OrderBy(i => i.ItemSpec))\n\t\t\t  {\n\t\t\t\t  Log.LogMessage(MessageImportance.High, \"{0}: {1}\", itemName, item.ItemSpec);\n\t\t\t\t  foreach (var name in item.MetadataNames.OfType<string>().OrderBy(_ => _))\n\t\t\t\t  {\n\t\t\t\t\t  try\n\t\t\t\t\t  {\n\t\t\t\t\t\t  Log.LogMessage(MessageImportance.High, \"\\t{0}={1}\", name, item.GetMetadata(name));\n\t\t\t\t\t  }\n\t\t\t\t\t  catch { }\n\t\t\t\t  }\n\t\t\t  }\n      ]]>\n      </Code>\n    </Task>\n  </UsingTask>\n\n</Project>\n"
  },
  {
    "path": "src/SmallSharp/TaskItemFactory.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Build.Utilities;\n\nnamespace SmallSharp;\n\nstatic class TaskItemFactory\n{\n    public static TaskItem NewTaskItem(string itemSpec, Dictionary<string, string> metadata) => new(itemSpec, metadata);\n\n    public static TaskItem NewTaskItem(string itemSpec, params (string Key, string Value)[] metadata)\n        => new(itemSpec, metadata.ToDictionary(x => x.Key, x => x.Value));\n}\n"
  },
  {
    "path": "src/SmallSharp/readme.md",
    "content": "﻿[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](osmfeula.txt)\n[![OSS](https://img.shields.io/github/license/devlooped/oss.svg?color=blue)](license.txt) \n<!-- include ../../readme.md#description -->\n<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->\n<!-- include ../../readme.md#content -->\n<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->\n<!-- exclude -->"
  },
  {
    "path": "src/_._",
    "content": ""
  },
  {
    "path": "src/demo.ps1",
    "content": "pushd $PSScriptRoot/..\ndotnet build -p:PackOnBuild=true\n$version = gci bin | select -first 1 -expandproperty BaseName | %{ $_.Substring(11) }\npushd src/Demo\njq --arg version \"$version\" '.[\"msbuild-sdks\"].SmallSharp = $version' global.json > temp.json && del global.json && mv temp.json global.json\n\n# build with each top-level file as the active one\nforeach ($file in gci *.cs) {\n    # rm -r -fo obj -ea 0\n    dotnet build Demo.csproj -p:start=$($file.Name) -bl:\"$($file.BaseName).binlog\"\n    if ($LASTEXITCODE -ne 0) {\n        Write-Error \"Build failed for $($file.Name)\"\n        popd; popd;\n        exit $LASTEXITCODE\n    }\n}\n\npopd; popd;\n"
  },
  {
    "path": "src/nuget.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <config>\n      <add key=\"signatureValidationMode\" value=\"accept\" />\n    </config>\n    <trustedSigners>\n      <author name=\"Microsoft\">\n        <certificate fingerprint=\"3F9001EA83C560D712C24CF213C3D312CB3BFF51EE89435D3430BD06B5D0EECE\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"AA12DA22A49BCE7D5C1AE64CC1F3D892F150DA76140F210ABD2CBFFCA2C18A27\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"566A31882BE208BE4422F7CFD66ED09F5D4524A5994F50CCC8B05EC0528C1353\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"1F4B311D9ACC115C8DC8018B5A49E00FCE6DA8E2855F9F014CA6F34570BC482D\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n      </author>\n      <repository name=\"nuget.org\" serviceIndex=\"https://api.nuget.org/v3/index.json\">\n        <certificate fingerprint=\"0E5F38F57DC1BCC806D8494F4F90FBCEDD988B46760709CBEEC6F4219AA6157D\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"5A2901D6ADA3D18260B9C6DFE2133C95D74B9EEF6AE0E5DC334C8454D1477DF4\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"CF7AC17AD047ECD5FDC36822031B12D4EF078B6F2B4C5E6BA41F8FF2CF4BAD67\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"C474CE76007D02394E0DA5E4DE7C14C680F9E282013CFEF653EF5DB71FDF61F8\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n        <certificate fingerprint=\"1F4B311D9ACC115C8DC8018B5A49E00FCE6DA8E2855F9F014CA6F34570BC482D\" hashAlgorithm=\"SHA256\" allowUntrustedRoot=\"true\" />\n      </repository>\n    </trustedSigners>\n</configuration>\n"
  }
]