Full Code of Floogen/Stardrop for AI

development c1c3c243e033 cached
139 files
804.5 KB
191.0k tokens
432 symbols
1 requests
Download .txt
Showing preview only (894K chars total). Download the full file or copy to clipboard to get everything.
Repository: Floogen/Stardrop
Branch: development
Commit: c1c3c243e033
Files: 139
Total size: 804.5 KB

Directory structure:
gitextract_noi0fdfa/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── nightly-build.yml
│       ├── package-and-release.yml
│       ├── package.yml
│       ├── pr-target-action.yml
│       └── version-build.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
└── Stardrop/
    ├── App.axaml
    ├── App.axaml.cs
    ├── Assets/
    │   ├── Info.plist
    │   ├── Stardrop.icns
    │   └── Stardrop.sh
    ├── Converters/
    │   ├── EnumConverter.cs
    │   └── EnumEqualsConverter.cs
    ├── Models/
    │   ├── Config.cs
    │   ├── Data/
    │   │   ├── ClientData.cs
    │   │   ├── Enums/
    │   │   │   ├── Choice.cs
    │   │   │   ├── DisplayFilter.cs
    │   │   │   ├── EndorsementResponse.cs
    │   │   │   ├── InstallState.cs
    │   │   │   ├── ModGrouping.cs
    │   │   │   └── NexusServers.cs
    │   │   ├── LastSessionData.cs
    │   │   ├── ModDownloadEvents.cs
    │   │   ├── ModInstallData.cs
    │   │   ├── ModKeyInfo.cs
    │   │   ├── ModUpdateInfo.cs
    │   │   ├── PairedKeys.cs
    │   │   └── UpdateCache.cs
    │   ├── Mod.cs
    │   ├── Nexus/
    │   │   ├── NexusUser.cs
    │   │   └── Web/
    │   │       ├── DownloadLink.cs
    │   │       ├── Endorsement.cs
    │   │       ├── EndorsementResult.cs
    │   │       ├── ModDetails.cs
    │   │       ├── ModFile.cs
    │   │       ├── ModFiles.cs
    │   │       ├── NXM.cs
    │   │       ├── NexusConnectionResult.cs
    │   │       ├── Validate.cs
    │   │       ├── WebsocketResponse.cs
    │   │       └── WebsocketResponseData.cs
    │   ├── Profile.cs
    │   ├── SMAPI/
    │   │   ├── Converters/
    │   │   │   ├── BooleanConverter.cs
    │   │   │   ├── BooleanConverterAssumeTrue.cs
    │   │   │   └── ModKeyConverter.cs
    │   │   ├── GameDetails.cs
    │   │   ├── Manifest.cs
    │   │   ├── ManifestContentPackFor.cs
    │   │   ├── ManifestDependency.cs
    │   │   └── Web/
    │   │       ├── ModEntry.cs
    │   │       ├── ModEntryMetadata.cs
    │   │       ├── ModEntryVersion.cs
    │   │       ├── ModSearchData.cs
    │   │       └── ModSearchEntry.cs
    │   ├── Settings.cs
    │   └── Theme.cs
    ├── Program.cs
    ├── Properties/
    │   └── PublishProfiles/
    │       ├── FolderProfile - Linux.pubxml
    │       ├── FolderProfile - MacOS.pubxml
    │       └── FolderProfile - Windows.pubxml
    ├── Stardrop.csproj
    ├── Stardrop.sln
    ├── Themes/
    │   ├── Contributors/
    │   │   └── hotcereal/
    │   │       ├── CASH MONEY.xaml
    │   │       ├── Cerene Dark.xaml
    │   │       ├── Cerene Light.xaml
    │   │       ├── Dark Cherry Chocolate.xaml
    │   │       ├── Fairy.xaml
    │   │       ├── Forest.xaml
    │   │       ├── Light (Pink).xaml
    │   │       └── Light Cherry Chocolate.xaml
    │   ├── Dark.xaml
    │   ├── Light.xaml
    │   ├── Solarized-Lite.xaml
    │   └── Stardrop.xaml
    ├── Utilities/
    │   ├── Extension/
    │   │   └── TranslateExtension.cs
    │   ├── External/
    │   │   ├── GitHub.cs
    │   │   ├── NexusClient.cs
    │   │   ├── NexusDownloadResult.cs
    │   │   └── SMAPI.cs
    │   ├── Helper.cs
    │   ├── Internal/
    │   │   ├── EnumParser.cs
    │   │   └── ManifestParser.cs
    │   ├── JsonTools.cs
    │   ├── NXMProtocol.cs
    │   ├── NexusWebsocket.cs
    │   ├── Pathing.cs
    │   ├── SimpleObscure.cs
    │   └── Translation.cs
    ├── ViewLocator.cs
    ├── ViewModels/
    │   ├── DownloadPanelViewModel.cs
    │   ├── FlexibleOptionWindowViewModel.cs
    │   ├── MainWindowViewModel.cs
    │   ├── MessageWindowViewModel.cs
    │   ├── ModDownloadViewModel.cs
    │   ├── ProfileEditorViewModel.cs
    │   ├── SettingsWindowViewModel.cs
    │   ├── ViewModelBase.cs
    │   └── WarningWindowViewModel.cs
    ├── Views/
    │   ├── DownloadPanel.axaml
    │   ├── DownloadPanel.axaml.cs
    │   ├── FlexibleOptionWindow.axaml
    │   ├── FlexibleOptionWindow.axaml.cs
    │   ├── MainWindow.axaml
    │   ├── MainWindow.axaml.cs
    │   ├── MessageWindow.axaml
    │   ├── MessageWindow.axaml.cs
    │   ├── NexusInfo.axaml
    │   ├── NexusInfo.axaml.cs
    │   ├── NexusLogin.axaml
    │   ├── NexusLogin.axaml.cs
    │   ├── ProfileEditor.axaml
    │   ├── ProfileEditor.axaml.cs
    │   ├── ProfileNaming.axaml
    │   ├── ProfileNaming.axaml.cs
    │   ├── SettingsWindow.axaml
    │   ├── SettingsWindow.axaml.cs
    │   ├── WarningWindow.axaml
    │   └── WarningWindow.axaml.cs
    └── i18n/
        ├── de.json
        ├── default.json
        ├── es.json
        ├── fr.json
        ├── hu.json
        ├── it.json
        ├── ja.json
        ├── ko.json
        ├── pl.json
        ├── pt.json
        ├── ru.json
        ├── th.json
        ├── tr.json
        ├── uk.json
        └── zh.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
*    text=auto
*.sh text      eol=lf


================================================
FILE: .github/workflows/build.yml
================================================
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net

name: Build

on:
  push:
    branches: [ "stable" ]
  pull_request:
    types:
      - opened
      - edited
      - reopened
      - synchronize
  workflow_call:
  workflow_dispatch:

env:
  WORKING_DIRECTORY: "Stardrop"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Setup .NET
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: 8.0.x
    - name: Restore dependencies
      run: dotnet restore "${{ env.WORKING_DIRECTORY }}"
    - name: Build
      run: dotnet build "${{ env.WORKING_DIRECTORY }}" --no-restore


================================================
FILE: .github/workflows/nightly-build.yml
================================================
name: Package Nightly Build

on:
  schedule:
    - cron: '0 10 * * *'
  workflow_dispatch:

permissions:
  contents: write

jobs:
    package-and-release:
      uses: ./.github/workflows/package-and-release.yml
      with:
        tag: nightly
        is-prerelease: 'true'
        generate-release-notes: false


================================================
FILE: .github/workflows/package-and-release.yml
================================================
name: Package and Release

on:
  workflow_call:
    inputs:
      tag:
        required: false
        type: string
        default: ''
      is-prerelease:
        required: true
        type: string
      generate-release-notes:
        required: true
        type: boolean
        default: true
  workflow_dispatch:
    inputs:
      tag:
        required: true
        type: string
      is-prerelease:
        required: true
        type: choice
        options:
        - 'true'
        - 'false'
      generate-release-notes:
        required: true
        type: boolean
        default: true

env:
  TAG: ${{ inputs.tag == '' && github.ref_name || inputs.tag }}
  
permissions:
  contents: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
  group: "releasing"
  cancel-in-progress: false

run-name: "[${{ inputs.is-prerelease == 'true' && 'Pre-release' || 'Release' }}] Package and Release (${{ inputs.tag == '' && github.ref_name || inputs.tag }})"

jobs:
  verify-build:
    uses: ./.github/workflows/build.yml
  package:  
    needs: [ verify-build ]
    uses: ./.github/workflows/package.yml
    with:
        branch-name: '' # Leaving blank to use default branch
  release:
    runs-on: ubuntu-latest
    needs: [ verify-build, package ]

    steps:
    - uses: actions/checkout@v4
    - uses: actions/download-artifact@v4    
      with:
        merge-multiple: true
    - name: Release
      uses: softprops/action-gh-release@v2
      with:
        tag_name: ${{ env.TAG }}
        prerelease: ${{ inputs.is-prerelease }}
        name: "Stardrop ${{ env.TAG }}"
        append_body: false
        body: |
          ![Downloads](https://img.shields.io/github/downloads/Floogen/Stardrop/${{ env.TAG }}/Stardrop-linux-x64.zip?label=Linux+Downloads) ![Downloads](https://img.shields.io/github/downloads/Floogen/Stardrop/${{ env.TAG }}/Stardrop-osx-x64.zip?label=macOS+Downloads) ![Downloads](https://img.shields.io/github/downloads/Floogen/Stardrop/${{ env.TAG }}/Stardrop-win-x64.zip?label=Windows+Downloads)
          
          Documentation can be [found here](https://floogen.gitbook.io/stardrop/).
          
          **User Note:**
          Download the respective ZIP file relating to the host's operating system (Stardrop-win-x64 if using a Window x64 OS and so on).
                
          <br/>
        generate_release_notes: ${{ inputs.generate-release-notes }}
        make_latest: true
        fail_on_unmatched_files: true
        files: |
          Stardrop-win-x64.zip
          Stardrop-linux-x64.zip
          Stardrop-osx-x64.zip


================================================
FILE: .github/workflows/package.yml
================================================
name: Package

on:
  pull_request:
    types:
      - labeled
      - unlabeled
      - opened
      - edited
      - reopened
      - synchronize
  workflow_call:
    inputs:
      branch-name:
        required: true
        type: string
  workflow_dispatch:
    inputs:
      branch-name:
        required: true
        type: string

env:
  OUTPUT_PATH_WINDOWS: published/windows
  OUTPUT_PATH_LINUX: published/linux
  OUTPUT_PATH_MAC: published/mac  
  CONFIGURATION: Release
  WORKING_DIRECTORY: "Stardrop"
  BRANCH: ${{ github.event_name != 'pull_request' && inputs.branch-name || github.event.pull_request.head.ref }}

run-name: "[${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || 'Default Branch' }}] Packaging"

jobs:  
  package-macos:  
    if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'generate packages')
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v4
      with:
          ref: ${{ env.BRANCH }}
          repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
    - run: mkdir -p path/to/release-artifacts
    - name: Publish (MacOS - Creating)
      run:  |
          mkdir -p "${{ env.OUTPUT_PATH_MAC }}/Stardrop.app/Contents/MacOS"
          mkdir -p "${{ env.OUTPUT_PATH_MAC }}/Stardrop.app/Contents/Resources"
          dotnet publish "${{ env.WORKING_DIRECTORY }}" --output "${{ env.OUTPUT_PATH_MAC }}/Stardrop.app/Contents/MacOS" --configuration "${{ env.CONFIGURATION }}" --runtime "osx-x64" --framework "net8.0" --self-contained
    - name: Publish (MacOS - Packaging)
      working-directory: "${{ env.OUTPUT_PATH_MAC }}/Stardrop.app"
      run:  |
          cp ${GITHUB_WORKSPACE}/Stardrop/Assets/Info.plist "Contents/Info.plist"
          cp ${GITHUB_WORKSPACE}/Stardrop/Assets/Stardrop.icns "Contents/Resources/Stardrop.icns"

          chmod +x "Contents/MacOS/Stardrop"
          (cd ../ && codesign --force --deep -s - Stardrop.app)
          
          (cd ../ && zip -r ${GITHUB_WORKSPACE}/Stardrop-osx-x64.zip "Stardrop.app")
    - name: Upload artifacts
      uses: actions/upload-artifact@v4
      with:
        name: release-artifacts-macos
        path: |
          Stardrop-osx-x64.zip
  package-linux:  
    if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'generate packages')
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
      with:
          ref: ${{ env.BRANCH }}
          repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
    - run: mkdir -p path/to/release-artifacts
    - name: Publish (Linux - Creating)
      run:  |
          dotnet publish "${{ env.WORKING_DIRECTORY }}" --output "${{ env.OUTPUT_PATH_LINUX }}/Stardrop" --configuration "${{ env.CONFIGURATION }}" --runtime "linux-x64" --framework "net8.0" --self-contained
    - name: Publish (Linux - Packaging)
      working-directory: "${{ env.OUTPUT_PATH_LINUX }}/Stardrop"
      run:  |
          mv Stardrop Internal
          mv Stardrop.pdb Internal.pdb

          cp ${GITHUB_WORKSPACE}/Stardrop/Assets/Stardrop.sh Stardrop.sh

          chmod 755 ../Stardrop
          chmod +x Stardrop.sh
          chmod 644 Internal
          chmod 644 Internal.pdb
          
          (cd ../ && zip -r ${GITHUB_WORKSPACE}/Stardrop-linux-x64.zip "Stardrop")
    - name: Upload artifacts
      uses: actions/upload-artifact@v4
      with:
        name: release-artifacts-linux
        path: |
          Stardrop-linux-x64.zip
  package-windows:
    if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'generate packages')
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
      with:
          ref: ${{ env.BRANCH }}
          repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
    - run: mkdir -p path/to/release-artifacts
    - name: Publish (Windows - Creating & Packaging)
      run:  |
          dotnet publish "${{ env.WORKING_DIRECTORY }}" --output "${{ env.OUTPUT_PATH_WINDOWS }}/Stardrop" --configuration "${{ env.CONFIGURATION }}" --runtime "win-x64" --framework "net8.0" --self-contained
          (cd "${{ env.OUTPUT_PATH_WINDOWS }}" && zip -r ${GITHUB_WORKSPACE}/Stardrop-win-x64.zip "Stardrop")
    - name: Upload artifacts
      uses: actions/upload-artifact@v4
      with:
        name: release-artifacts-windows
        path: |
          Stardrop-win-x64.zip


================================================
FILE: .github/workflows/pr-target-action.yml
================================================
name: PR Target Check

on:
  pull_request:
    types:
      - opened
      - edited
      - reopened
      - synchronize
  
jobs:
  is-using-correct-target:
    runs-on: ubuntu-latest
    steps:
      - name: Check branches
        run: |
          if [ ${{ github.base_ref }} == "stable" ] && [ ${{ github.head_ref }} != "development" ]; then
            echo "Merge requests to the stable branch are only allowed from the development branch."
            exit 1
          fi


================================================
FILE: .github/workflows/version-build.yml
================================================
name: Package Version Release

on:
  push:
    tags:
      - "v*.*.*"

permissions:
  contents: write

jobs:
    package-and-release:
      uses: ./.github/workflows/package-and-release.yml
      with:
        tag: ${{ github.ref_name }}
        is-prerelease: ${{ contains(github.ref_name, '-beta') && 'true' || 'false' }}
        generate-release-notes: true


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/



================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: CONTRIBUTING.md
================================================
If reporting an issue with Stardrop, please ensure that a copy of Stardrop's log is attached.

The log file can be found via Stardrop's menu under `View` > `Log File`.


================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: README.md
================================================
# Stardrop
 
Stardrop is an open-source, cross-platform mod manager for the game [Stardew Valley](https://www.stardewvalley.net/). It is built using the Avalonia UI framework.

Stadrop utilizes [SMAPI (Stardew Modding API)](https://smapi.io/) to simplify the management and update checking for all applicable Stardew Valley mods.

Profiles are also supported, allowing users to have multiple mod groups for specific gameplay or multiplayer sessions.

# Getting Started

See the [GitBook pages](https://floogen.gitbook.io/stardrop/) for detailed documentation on how to install, update and use Stardrop.

## Downloading Stardrop

See the [release page](https://github.com/Floogen/Stardrop/releases/latest) for the latest builds.

# Credits
## Translations
Stardrop has been generously translated into several languages by the following users:

* **Chinese** - guanyintu, PIut02, Z2549, CuteCat233
* **French** - xynerorias
* **German** - Schn1ek3
* **Hungarian** - martin66789
* **Italian** - S-zombie
* **Japanese** - OishiiUnichan
* **Korean** - buriburishoebill
* **Polish** - Naciux
* **Portuguese** - aracnus
* **Russian** - Rongarah
* **Spanish** - Evexyron, Gaelhaine
* **Thai** - ellipszist
* **Turkish** - KediDili
* **Ukrainian** - burunduk, ChulkyBow, DanielleTlumach

# Gallery

![](https://imgur.com/WdjwfnG.gif)

![](https://imgur.com/kalsOjS.gif)


================================================
FILE: Stardrop/App.axaml
================================================
<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:Stardrop"
             x:Class="Stardrop.App"
             Name="Stardrop">
	<Application.DataTemplates>
		<local:ViewLocator/>
	</Application.DataTemplates>

	<Application.Styles>
		<FluentTheme Mode="Light" />
		<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
	</Application.Styles>
</Application>


================================================
FILE: Stardrop/App.axaml.cs
================================================
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using Stardrop.Models.Nexus.Web;
using Stardrop.Utilities;
using Stardrop.Utilities.External;
using Stardrop.Views;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Stardrop
{
    public class App : Application
    {
        public override void Initialize()
        {
            AvaloniaXamlLoader.Load(this);

            // Verify that the helper is instantiated, if it isn't then this code is likely reached by Avalonia's previewer and bypassed Main
            if (Program.helper is null)
            {
                Program.helper = new Helper();
            }

            // Load in translations
            Program.translation.LoadTranslations();

            // Handle adding the themes
            Dictionary<string, IStyle> themes = new Dictionary<string, IStyle>();
            foreach (string fileFullName in Directory.EnumerateFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Themes"), "*.xaml", SearchOption.AllDirectories))
            {
                try
                {
                    var themeName = Path.GetFileNameWithoutExtension(fileFullName);
                    themes[themeName] = AvaloniaRuntimeXamlLoader.Parse<Styles>(File.ReadAllText(fileFullName));
                    Program.helper.Log($"Loaded theme {Path.GetFileNameWithoutExtension(fileFullName)}", Helper.Status.Debug);
                }
                catch (Exception ex)
                {
                    Program.helper.Log($"Unable to load theme on {Path.GetFileNameWithoutExtension(fileFullName)}: {ex}", Helper.Status.Warning);
                }
            }

            Current.Styles.Insert(0, !themes.ContainsKey(Program.settings.Theme) ? themes.Values.First() : themes[Program.settings.Theme]);
        }

        private async void OnUrlsOpen(object? sender, UrlOpenedEventArgs e, MainWindow mainWindow)
        {
            foreach (string? url in e.Urls.Where(u => String.IsNullOrEmpty(u) is false))
            {
                await mainWindow.ProcessNXMLink(new NXM() { Link = url, Timestamp = DateTime.Now });
            }
        }

        public override void OnFrameworkInitializationCompleted()
        {
            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                var mainWindow = new MainWindow();
                desktop.MainWindow = mainWindow;

                // Register events
                this.UrlsOpened += (sender, e) => OnUrlsOpen(sender, e, mainWindow);
            }

            base.OnFrameworkInitializationCompleted();
        }
    }
}


================================================
FILE: Stardrop/Assets/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>CFBundleInfoDictionaryVersion</key>
		<string>6.0</string>
		<key>CFBundlePackageType</key>
		<string>APPL</string>
		<key>CFBundleIconFile</key>
		<string>Stardrop</string>
		<key>CFBundleSignature</key>
		<string>com.Floogen.Stardrop</string>
		<key>CFBundleName</key>
		<string>Stardrop</string>
		<key>CFBundleExecutable</key>
		<string>Stardrop</string>
		<key>CFBundleIdentifier</key>
		<string>stardrop</string>
		<key>CFBundleVersion</key>
		<string>1.0.0</string>
		<key>CFBundleShortVersionString</key>
		<string>1.0</string>
		<key>CFBundleURLTypes</key>
		<array>
			<dict>
				<key>CFBundleURLName</key>
				<string>NXM</string>
				<key>CFBundleURLSchemes</key>
				<array>
					<string>nxm</string>
				</array>
			</dict>
		</array>
		<key>NSHighResolutionCapable</key>
		<string>true</string>
	</dict>
</plist>

================================================
FILE: Stardrop/Assets/Stardrop.sh
================================================
#!/usr/bin/env bash
chmod u+x ./Internal
./Internal


================================================
FILE: Stardrop/Converters/EnumConverter.cs
================================================
using Avalonia.Data.Converters;
using System;
using System.Globalization;

namespace Stardrop.Converters
{
    public class EnumConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Enum.GetName((value.GetType()), value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}


================================================
FILE: Stardrop/Converters/EnumEqualsConverter.cs
================================================
using Avalonia.Data.Converters;
using System;
using System.Globalization;

namespace Stardrop.Converters
{
    public class EnumEqualsConverter : IValueConverter
    {
        public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
        {
            if (value?.GetType()?.IsEnum is not true)
            {
                throw new ArgumentOutOfRangeException(nameof(value), "Value must be a non-null enum.");
            }
            if (parameter?.GetType()?.IsEnum is not true)
            {
                throw new ArgumentOutOfRangeException(nameof(parameter), "Parameter must be a non-null enum.");
            }

            return Enum.Equals(value, parameter);
        }

        public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}


================================================
FILE: Stardrop/Models/Config.cs
================================================
using System;

namespace Stardrop.Models
{
    public class Config
    {
        public string UniqueId { get; set; }
        public string FilePath { get; set; }
        public DateTime LastWriteTimeUtc { get; set; }
        public string Data { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/ClientData.cs
================================================
using System.Collections.Generic;

namespace Stardrop.Models.Data
{
    public class ClientData
    {
        public List<ModInstallData> ModInstallData { get; set; }
        public Dictionary<string, bool> ColumnActiveStates { get; set; } = new Dictionary<string, bool>();
        public LastSessionData LastSessionData { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/Choice.cs
================================================
namespace Stardrop.Models.Data.Enums
{
    public enum Choice
    {
        First,
        Second,
        Third
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/DisplayFilter.cs
================================================
namespace Stardrop.Models.Data.Enums
{
    public enum DisplayFilter
    {
        None,
        ShowEnabled,
        ShowDisabled,
        RequireConfig
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/EndorsementResponse.cs
================================================
namespace Stardrop.Models.Data.Enums
{
    public enum InstallState
    {
        Unknown,
        Downloading,
        Installing
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/InstallState.cs
================================================
namespace Stardrop.Models.Data.Enums
{
    public enum EndorsementResponse
    {
        Unknown,
        IsOwnMod,
        TooSoonAfterDownload,
        NotDownloadedMod,
        Abstained,
        Endorsed
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/ModGrouping.cs
================================================
using System.ComponentModel;

namespace Stardrop.Models.Data.Enums
{
    public enum ModGrouping
    {
        None,
        Folder,
        [Description("Content Pack")]
        ContentPack,
        [Description("Folder (Condensed)")]
        FolderCondensed
    }
}


================================================
FILE: Stardrop/Models/Data/Enums/NexusServers.cs
================================================
using System.ComponentModel;

namespace Stardrop.Models.Data.Enums
{
    public enum NexusServers
    {
        [Description("Nexus CDN")]
        NexusCDN,
        Chicago,
        Paris,
        Amsterdam,
        Prague,
        [Description("Los Angeles")]
        LosAngeles,
        Miami,
        Singapore
    }
}


================================================
FILE: Stardrop/Models/Data/LastSessionData.cs
================================================
using Avalonia;
using System;

namespace Stardrop.Models.Data
{
    public class LastSessionData
    {
        public double Height { get; set; } = 800;
        public double Width { get; set; } = 1430;
        public int PositionX { get; set; }
        public int PositionY { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/ModDownloadEvents.cs
================================================
using System;
using System.Threading;

namespace Stardrop.Models.Data
{
    internal record ModDownloadStartedEventArgs(Uri Uri, string Name, long? Size, CancellationTokenSource DownloadCancellationSource);    
    internal record ModDownloadProgressEventArgs(Uri Uri, long TotalBytes);
    internal record ModDownloadCompletedEventArgs(Uri Uri);
    internal record ModDownloadFailedEventArgs(Uri Uri);
}


================================================
FILE: Stardrop/Models/Data/ModInstallData.cs
================================================
using System;

namespace Stardrop.Models.Data
{
    public class ModInstallData
    {
        public string UniqueId { get; set; }
        public DateTime InstallTimestamp { get; set; }
        public DateTime? LastUpdateTimestamp { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/ModKeyInfo.cs
================================================
namespace Stardrop.Models.Data
{
    public class ModKeyInfo
    {
        public string UniqueId { get; set; }
        public string Name { get; set; }
        public string PageUrl { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/ModUpdateInfo.cs
================================================
using static Stardrop.Models.SMAPI.Web.ModEntryMetadata;

namespace Stardrop.Models.Data
{
    public class ModUpdateInfo
    {
        public string UniqueId { get; set; }
        public string SuggestedVersion { get; set; }
        public WikiCompatibilityStatus Status { get; set; }
        public string Link { get; set; }


        public ModUpdateInfo()
        {

        }

        public ModUpdateInfo(string uniqueId, string recommendedVersion, WikiCompatibilityStatus status, string link)
        {
            UniqueId = uniqueId;
            SuggestedVersion = recommendedVersion;
            Status = status;
            Link = link;
        }
    }
}


================================================
FILE: Stardrop/Models/Data/PairedKeys.cs
================================================
namespace Stardrop.Models.Data
{
    public class PairedKeys
    {
        public byte[] Lock { get; set; }
        public byte[] Vector { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Data/UpdateCache.cs
================================================
using System;
using System.Collections.Generic;

namespace Stardrop.Models.Data
{
    public class UpdateCache
    {
        public DateTime LastRuntime { get; set; }
        public List<ModUpdateInfo> Mods { get; set; }

        public UpdateCache(DateTime lastRuntime)
        {
            LastRuntime = lastRuntime;
            Mods = new List<ModUpdateInfo>();
        }
    }
}


================================================
FILE: Stardrop/Models/Mod.cs
================================================
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Semver;
using Stardrop.Models.Data.Enums;
using Stardrop.Models.SMAPI;
using Stardrop.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using static Stardrop.Models.SMAPI.Web.ModEntryMetadata;

namespace Stardrop.Models
{
    public class Mod : INotifyPropertyChanged
    {
        internal readonly FileInfo ModFileInfo;
        internal readonly Manifest Manifest;

        public string UniqueId { get; set; }
        public SemVersion Version { get; set; }
        public string ParsedVersion { get { return Version.ToString(); } }
        public string SuggestedVersion { get; set; }
        public string Name { get; set; }
        public string Path { get { return _path; } set { _path = value; RootPath = GetRootPath(value); } } // Whole mod path inside installed mods path for grouping mod components in the same mod
        private string _path { get; set; }
        public string RootPath { get; private set; } // Root mod path inside installed mods path for grouping mod components in the same mod
        public string ManifestFilePath { get { return ModFileInfo.FullName; } }
        public string Description { get; set; }
        public string Summary { get { return $"Author: {Author}\nVersion: {ParsedVersion}\nHas Config: {HasConfig}\n\n{Description}"; } }
        public string Author { get; set; }
        public DateTime? InstallTimestamp { get; set; }
        public DateTime? LastUpdateTimestamp { get; set; }
        public Config? _config { get; set; }
        public Config? Config { get { return _config; } set { _config = value; NotifyPropertyChanged("Config"); NotifyPropertyChanged("HasConfig"); } }
        public bool HasConfig { get { return Config is not null; } }
        public string FrameworkID { get; set; } = string.Empty;
        private List<ManifestDependency> _requirements { get; set; }
        public List<ManifestDependency> Requirements { get { return _requirements; } set { _requirements = value; NotifyPropertyChanged("Requirements"); NotifyPropertyChanged("MissingRequirements"); NotifyPropertyChanged("HardRequirements"); } }
        public List<ManifestDependency> MissingRequirements { get { return _requirements is null ? null : _requirements.Where(r => !String.IsNullOrEmpty(r.Name) && r.IsMissing && r.IsRequired).ToList(); } }
        public List<ManifestDependency> HardRequirements { get { return _requirements is null ? null : _requirements.Where(r => !String.IsNullOrEmpty(r.Name) && !r.IsMissing && r.IsRequired).ToList(); } }
        private string _updateUri { get; set; }
        public string UpdateUri { get { return _updateUri; } set { _updateUri = value; NotifyPropertyChanged("UpdateUri"); } }
        private string _modPageUri { get; set; }
        public string ModPageUri { get { return _modPageUri; } set { _modPageUri = value; NotifyPropertyChanged("ModPageUri"); } }
        public int? NexusModId { get { return GetNexusId(); } }
        private string? _nexusModThumbnailPath { get; set; }
        public string? NexusModThumbnailPath { get { return _nexusModThumbnailPath; } set { _nexusModThumbnailPath = value; NexusModThumbnailFile = TryLoadThumbnail(value); NotifyPropertyChanged("NexusModThumbnailFile"); } }
        public Bitmap? NexusModThumbnailFile { get; set; }
        private bool _isEnabled { get; set; }
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                NotifyPropertyChanged("IsEnabled");
                NotifyPropertyChanged("ChangeStateText");
                NotifyPropertyChanged("ChangeWholeModGroupStateText");
            }
        }
        private bool _isHidden { get; set; }
        public bool IsHidden { get { return _isHidden; } set { _isHidden = value; NotifyPropertyChanged("IsHidden"); } }
        private bool _isEndorsement { get; set; }
        public bool IsEndorsed { get { return _isEndorsement; } set { _isEndorsement = value; NotifyPropertyChanged("IsEndorsed"); } }
        public string ChangeStateText { get { return IsEnabled ? Program.translation.Get("internal.disable") : Program.translation.Get("internal.enable"); } }
        public string ChangeWholeModGroupStateText { get { return IsEnabled ? Program.translation.Get("internal.disable_whole_mod") : Program.translation.Get("internal.enable_whole_mod"); } }
        private WikiCompatibilityStatus _status { get; set; }
        public WikiCompatibilityStatus Status { get { return _status; } set { _status = value; NotifyPropertyChanged("Status"); NotifyPropertyChanged("ParsedStatus"); NotifyPropertyChanged("InstallStatus"); } }
        public string ParsedStatus
        {
            get
            {
                if (!String.IsNullOrEmpty(SuggestedVersion) && IsModOutdated(SuggestedVersion))
                {
                    if (_status == WikiCompatibilityStatus.Unofficial)
                    {
                        return String.Format(Program.translation.Get("ui.main_window.hyperlinks.unofficial_update_available"), SuggestedVersion);
                    }
                    return String.Format(Program.translation.Get("ui.main_window.hyperlinks.update_available"), SuggestedVersion);
                }
                else if (_status == WikiCompatibilityStatus.Broken)
                {
                    return Program.translation.Get("ui.main_window.hyperlinks.broken_compatibility_issue");
                }

                return String.Empty;
            }
        }
        private InstallState _installState { get; set; }
        public InstallState InstallState { get { return _installState; } set { _installState = value; NotifyPropertyChanged("InstallState"); NotifyPropertyChanged("InstallStatus"); } }
        public string InstallStatus
        {
            get
            {
                if (!String.IsNullOrEmpty(SuggestedVersion) && IsModOutdated(SuggestedVersion))
                {
                    var nexusModId = GetNexusId();
                    if (_status == WikiCompatibilityStatus.Unofficial || nexusModId is null)
                    {
                        return String.Empty;
                    }
                    else if (InstallState == InstallState.Unknown)
                    {
                        return Program.translation.Get("ui.main_window.hyperlinks.install_update");
                    }

                    return InstallState == InstallState.Downloading ? Program.translation.Get("ui.main_window.hyperlinks.downloading") : Program.translation.Get("ui.main_window.hyperlinks.installing");
                }

                return String.Empty;
            }
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        public Mod(Manifest manifest, FileInfo modFileInfo, string uniqueId, string version, string? name = null, string? description = null, string? author = null)
        {
            Manifest = manifest;
            ModFileInfo = modFileInfo;
            UniqueId = uniqueId;
            Version = SemVersion.TryParse(version, SemVersionStyles.Any, out var parsedVersion) ? parsedVersion : SemVersion.ParsedFrom(0, 0, 0, "bad-version");
            Name = String.IsNullOrEmpty(name) ? uniqueId : name;
            Path = ComputeModPath(modFileInfo);
            Description = String.IsNullOrEmpty(description) ? String.Empty : description;
            Author = String.IsNullOrEmpty(author) ? Program.translation.Get("internal.unknown") : author;
            Requirements = new List<ManifestDependency>();
        }

        /// <summary>
        /// Compute relative path to a mod from the installed mods path or default Stardew Valley mods path.
        /// </summary>
        private string ComputeModPath(FileInfo modFileInfo)
        {
            // Set whole mod path for grouping with other mods from the same mod.
            var commonNameInstalledFolder = Program.settings.ModInstallPath;
            var commonNameModsFolder = Program.settings.ModFolderPath;
            string modNamePath;
            if (System.IO.Path.EndsInDirectorySeparator(commonNameInstalledFolder))
            {
                commonNameInstalledFolder += System.IO.Path.DirectorySeparatorChar;
            }

            if (modFileInfo.DirectoryName.Contains(commonNameModsFolder))
            {
                // Mod inside default Stardew Valley mods folder.
                modNamePath = modFileInfo.DirectoryName.Substring(commonNameModsFolder.Length + 1);
            }
            else
            {
                throw new Exception($"Invalid mod folder path: {modFileInfo.DirectoryName}");
            }

            // TODO: Add program config option to switch between both approaches? And to disable grouping entirely?
            // For top-level folder grouping.
            // Producing group "automation" as a single group for both "automation/Automate" and
            //  "automation/Producer Framework Mod".
            // var foundIndex = modNamePath.IndexOf(System.IO.Path.DirectorySeparatorChar);
            // For subfolders-specific grouping.
            // Producing groups "automation/Automate" (with mods `[CP] Automate/manifest.json`, `[JA] Automate/manifest.json`)
            //  and "automation/Producer Framework Mod" (with mods `[CP] PFM` and `[JA] PFM`) folders as separate groups.
            var foundIndex = modNamePath.LastIndexOf(System.IO.Path.DirectorySeparatorChar);

            var nameLength = foundIndex == -1 ? modNamePath.Length : foundIndex;
            var finalPath = modNamePath.Substring(0, nameLength);
            return String.IsNullOrEmpty(finalPath) ? Program.translation.Get("internal.unknown") : finalPath;
        }

        private string GetRootPath(string path)
        {
            var foundIndex = path.IndexOf(System.IO.Path.DirectorySeparatorChar);
            if (foundIndex == -1)
            {
                return path;
            }

            return path.Substring(0, foundIndex);
        }

        public bool IsModOutdated(string version)
        {
            if (String.IsNullOrEmpty(version) || !HasValidVersion())
            {
                return false;
            }

            return SemVersion.Parse(version, SemVersionStyles.Any).CompareSortOrderTo(Version) > 0;
        }

        public bool HasValidVersion()
        {
            if (Version.Prerelease.Equals("bad-version", StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }

            return true;
        }

        public bool HasUpdateKeys()
        {
            if (Manifest is not null && Manifest.UpdateKeys is not null && !Manifest.UpdateKeys.Any(k => String.IsNullOrEmpty(k)))
            {
                return true;
            }

            return false;
        }

        public int? GetNexusId()
        {
            if (HasUpdateKeys() is false)
            {
                return null;
            }

            foreach (string key in Manifest.UpdateKeys)
            {
                string cleanedKey = String.Concat(key.Where(c => !Char.IsWhiteSpace(c)));
                var match = Regex.Match(key, @"Nexus:[^0-9-]*(?<modId>-?\d+)(?<flag>\@.*)?.*");
                if (match.Success)
                {
                    if (Int32.TryParse(match.Groups["modId"].ToString(), out int modId) && modId > 0)
                    {
                        return modId;
                    }
                }
            }

            return null;
        }

        public string? GetNexusFlag()
        {
            if (HasUpdateKeys() is false)
            {
                return null;
            }

            foreach (string key in Manifest.UpdateKeys)
            {
                string cleanedKey = String.Concat(key.Where(c => !Char.IsWhiteSpace(c)));
                var match = Regex.Match(key, @"Nexus:[^0-9-]*(?<modId>-?\d+)(?<flag>\@.*)?.*");
                if (match.Success)
                {
                    if (match.Groups.ContainsKey("flag"))
                    {
                        return match.Groups["flag"].ToString();
                    }
                }
            }

            return null;
        }
        
        private Bitmap? TryLoadThumbnail(string? filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return null;
            }

            try
            {
                var thumbnail = new Bitmap(filePath);
                return thumbnail;
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to load thumbnail for mod {UniqueId} using following path {filePath}");
                return null;
            }
        }

        internal void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}


================================================
FILE: Stardrop/Models/Nexus/NexusUser.cs
================================================
namespace Stardrop.Models.Nexus
{
    public class NexusUser
    {
        public string Username { get; set; }
        public bool IsPremium { get; set; }

        public byte[] Key { get; set; }

        public NexusUser()
        {

        }

        public NexusUser(string username, byte[] key)
        {
            Username = username;
            Key = key;
        }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/DownloadLink.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class DownloadLink
    {
        [JsonPropertyName("name")]
        public string? Name { get; set; }

        [JsonPropertyName("short_name")]
        public string? ShortName { get; set; }

        [JsonPropertyName("URI")]
        public string? Uri { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/Endorsement.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class EndorsementResult
    {
        [JsonPropertyName("message")]
        public string? Message { get; set; }

        [JsonPropertyName("status")]
        public string? Status { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/EndorsementResult.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class Endorsement
    {
        [JsonPropertyName("mod_id")]
        public int Id { get; set; }

        [JsonPropertyName("domain_name")]
        public string? DomainName { get; set; }

        [JsonPropertyName("status")]
        public string? Status { get; set; }

        public bool IsEndorsed()
        {
            if (Status?.ToUpper() == "ENDORSED")
            {
                return true;
            }

            return false;
        }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/ModDetails.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class ModDetails
    {
        [JsonPropertyName("name")]
        public string? Name { get; set; }

        [JsonPropertyName("picture_url")]
        public string? ThumbnailUrl { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/ModFile.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class ModFile
    {
        [JsonPropertyName("file_id")]
        public int Id { get; set; }

        [JsonPropertyName("file_name")]
        public string? Name { get; set; }

        [JsonPropertyName("description")]
        public string? Description { get; set; }

        [JsonPropertyName("version")]
        public string? Version { get; set; }

        [JsonPropertyName("category_name")]
        public string? Category { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/ModFiles.cs
================================================
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class ModFiles
    {
        [JsonPropertyName("files")]
        public List<ModFile> Files { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/NXM.cs
================================================
using System;

namespace Stardrop.Models.Nexus.Web
{
    public class NXM
    {
        public string? Link { get; set; }
        public DateTime Timestamp { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/NexusConnectionResult.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stardrop.Models.Nexus.Web
{
    public class NexusConnectionResult
    {
        public string? Error { get; set; }
        public string? Message { get; set; }

        public string? ApiKey { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/Validate.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.Nexus.Web
{
    public class Validate
    {
        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("is_premium")]
        public bool IsPremium { get; set; }

        [JsonPropertyName("profile_url")]
        public string ProfileUrl { get; set; }

        [JsonPropertyName("message")]
        public string Message { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/WebsocketResponse.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Stardrop.Models.Nexus.Web
{
    public class WebsocketResponse
    {
        [JsonPropertyName("success")]
        public bool Success { get; set; }

        [JsonPropertyName("data")]
        public WebsocketResponseData? Data { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Nexus/Web/WebsocketResponseData.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Stardrop.Models.Nexus.Web
{
    public class WebsocketResponseData
    {
        [JsonPropertyName("connection_token")]
        public string? ConnectionToken { get; set; }

        [JsonPropertyName("api_key")]
        public string? ApiKey { get; set; }
    }
}


================================================
FILE: Stardrop/Models/Profile.cs
================================================
using System.Collections.Generic;
using System.Text.Json;

namespace Stardrop.Models
{
    public class Profile
    {
        public string Name { get; set; }
        public bool IsProtected { get; set; }
        public List<string> EnabledModIds { get; set; }
        public Dictionary<string, JsonDocument> PreservedModConfigs { get; set; }

        public Profile()
        {
            Name = "Unknown";
            IsProtected = false;
            EnabledModIds = new List<string>();
            PreservedModConfigs = new Dictionary<string, JsonDocument>();
        }

        public Profile(string name, bool isProtected = false, List<string>? enabledMods = null, Dictionary<string, JsonDocument>? preservedModConfigs = null)
        {
            Name = name;
            IsProtected = isProtected;
            EnabledModIds = enabledMods is null ? new List<string>() : enabledMods;
            PreservedModConfigs = preservedModConfigs is null ? new Dictionary<string, JsonDocument>() : preservedModConfigs;
        }

        public Profile ShallowCopy()
        {
            return (Profile)this.MemberwiseClone();
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Converters/BooleanConverter.cs
================================================
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI.Converters
{
    internal class BooleanConverter : JsonConverter<bool>
    {
        public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False)
            {
                return reader.GetBoolean();
            }

            string value = reader.GetString();
            if (Boolean.TryParse(value, out bool result))
            {
                return result;
            }

            return false;
        }

        public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
        {
            throw new InvalidOperationException("This converter should not be used to write, it is read only.");
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Converters/BooleanConverterAssumeTrue.cs
================================================
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI.Converters
{
    internal class BooleanConverterAssumeTrue : JsonConverter<bool>
    {
        public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False)
            {
                return reader.GetBoolean();
            }

            string value = reader.GetString();
            if (Boolean.TryParse(value, out bool result))
            {
                return result;
            }

            return true;
        }

        public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
        {
            throw new InvalidOperationException("This converter should not be used to write, it is read only.");
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Converters/ModKeyConverter.cs
================================================
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI.Converters
{
    internal class ModKeyConverter : JsonConverter<string[]>
    {
        public override string[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartArray)
            {
                throw new JsonException();
            }

            var modKeys = new List<string>();
            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndArray)
                {
                    return modKeys.ToArray();
                }

                if (reader.TokenType == JsonTokenType.Number)
                {
                    modKeys.Add($"Nexus: {reader.GetInt32()}");
                }
                else
                {
                    modKeys.Add(reader.GetString());
                }
            }

            // Should not reach here, due to reader.TokenType == JsonTokenType.EndArray
            throw new JsonException();
        }

        public override void Write(Utf8JsonWriter writer, string[] value, JsonSerializerOptions options)
        {
            throw new InvalidOperationException("This converter should not be used to write, it is read only.");
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/GameDetails.cs
================================================
using Semver;
using System;

namespace Stardrop.Models.SMAPI
{
    public class GameDetails
    {
        public enum OS
        {
            Unknown,
            Linux,
            Mac,
            Windows
        }

        /// <summary>Stardew Valley's game version.</summary>
        public string GameVersion { get; set; }

        /// <summary>SMAPI's version.</summary>
        public string SmapiVersion { get; set; }

        /// <summary>The operating system.</summary>
        public OS System { get; set; }

        public GameDetails()
        {

        }

        public GameDetails(string gameVersion, string smapiVersion, string system)
        {
            GameVersion = gameVersion;
            if (GameVersion.Contains(' '))
            {
                GameVersion = GameVersion.Split(' ')[0];
            }
            SmapiVersion = smapiVersion;

            if (system.Contains("macOS", StringComparison.OrdinalIgnoreCase))
            {
                System = OS.Mac;
            }
            else if (system.Contains("Windows", StringComparison.OrdinalIgnoreCase))
            {
                System = OS.Windows;
            }
            else
            {
                System = OS.Linux;
            }
        }

        public bool HasSMAPIUpdated(string version)
        {
            if (String.IsNullOrEmpty(version))
            {
                return false;
            }

            return HasSMAPIUpdated(SemVersion.Parse(version));
        }

        public bool HasSMAPIUpdated(SemVersion version)
        {
            if (version is null)
            {
                return false;
            }

            return version != SemVersion.Parse(SmapiVersion);
        }

        public bool HasBadGameVersion()
        {
            if (GameVersion.Contains(' '))
            {
                return true;
            }

            return false;
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Manifest.cs
================================================
using Stardrop.Models.SMAPI.Converters;
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI
{
    public class Manifest
    {
        // Based on SMAPI's Manfiest.cs: https://github.com/Pathoschild/SMAPI/blob/c10685b03574e967c1bf48aafc814f60196812ec/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs

        /// <summary>The mod name.</summary>
        public string Name { get; set; }

        /// <summary>A brief description of the mod.</summary>
        public string Description { get; set; }

        /// <summary>The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</summary>
        [JsonConverter(typeof(ModKeyConverter))]
        public string[] UpdateKeys { get; set; }

        /// <summary>The mod author's name.</summary>
        public string Author { get; set; }

        /// <summary>The mod version.</summary>
        public string Version { get; set; }

        /// <summary>The unique mod ID.</summary>
        public string UniqueID { get; set; }

        /// <summary>The mod which will read this as a content pack. Mutually exclusive with <see cref="Manifest.EntryDll"/>.</summary>
        //[JsonConverter(typeof(ManifestContentPackForConverter))]
        public ManifestContentPackFor ContentPackFor { get; set; }

        /// <summary>The other mods that must be loaded before this mod.</summary>
        //[JsonConverter(typeof(ManifestDependencyArrayConverter))]
        public ManifestDependency[] Dependencies { get; set; }

        /// <summary>Custom property for Stardrop.</summary>
        public bool DeleteOldVersion { get; set; }

        /// <summary>Custom property for Stardrop.</summary>
        public string? UpdateCautionMessage { get; set; }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/ManifestContentPackFor.cs
================================================
namespace Stardrop.Models.SMAPI
{
    public class ManifestContentPackFor
    {
        // Based on SMAPI's IManifestContentPackFor.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit.CoreInterfaces/IManifestContentPackFor.cs

        /// <summary>The unique ID of the mod which can read this content pack.</summary>
        public string UniqueID { get; set; }

        /// <summary>The minimum required version (if any).</summary>
        public string MinimumVersion { get; set; }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/ManifestDependency.cs
================================================
using Stardrop.Models.SMAPI.Converters;
using System.ComponentModel;
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI
{
    public class ManifestDependency : INotifyPropertyChanged
    {
        // Based on SMAPI's IManifestDependency.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit.CoreInterfaces/IManifestDependency.cs

        /// <summary>The unique mod ID to require.</summary>
        public string UniqueID { get; set; }

        /// <summary>The minimum required version (if any).</summary>
        public string MinimumVersion { get; set; }

        /// <summary>Whether the dependency must be installed to use the mod.</summary>
        [JsonConverter(typeof(BooleanConverterAssumeTrue))]
        public bool IsRequired { get; set; }

        // <summary>Custom properties for Stardrop.</summary>
        private string _name { get; set; }
        public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged("Name"); NotifyPropertyChanged("GenericLink"); } }
        public bool IsMissing { get; set; }
        public string GenericLink { get { return $"https://smapi.io/mods#{Name.Replace(" ", "_")}"; } }

        public event PropertyChangedEventHandler? PropertyChanged;
        public ManifestDependency(string uniqueId, string minimumVersion, bool isRequired = true)
        {
            UniqueID = uniqueId;
            MinimumVersion = minimumVersion;
            IsRequired = isRequired;
        }

        private void NotifyPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Web/ModEntry.cs
================================================
namespace Stardrop.Models.SMAPI.Web
{
    public class ModEntry
    {
        // Based on SMAPI's ModEntryModel.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs

        /// <summary>The mod's unique ID.</summary>
        public string Id { get; set; }

        /// <summary>The update version recommended by the web API based on its version update and mapping rules.</summary>
        public ModEntryVersion SuggestedUpdate { get; set; }

        /// <summary>Optional extended data which isn't needed for update checks.</summary>
        public ModEntryMetadata Metadata { get; set; }

        /// <summary>The errors that occurred while fetching update data.</summary>
        public string[] Errors { get; set; } = new string[0];
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Web/ModEntryMetadata.cs
================================================
using System.Text.Json.Serialization;

namespace Stardrop.Models.SMAPI.Web
{
    public class ModEntryMetadata
    {
        // Based on SMAPI's WikiCompatibilityStatus.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs
        /// <summary>The compatibility status for a mod.</summary>
        public enum WikiCompatibilityStatus
        {
            /// <summary>The status is unknown.</summary>
            Unknown,

            /// <summary>The mod is compatible.</summary>
            Ok,

            /// <summary>The mod is compatible if you use an optional official download.</summary>
            Optional,

            /// <summary>The mod is compatible if you use an unofficial update.</summary>
            Unofficial,

            /// <summary>The mod isn't compatible, but the player can fix it or there's a good alternative.</summary>
            Workaround,

            /// <summary>The mod isn't compatible.</summary>
            Broken,

            /// <summary>The mod is no longer maintained by the author, and an unofficial update or continuation is unlikely.</summary>
            Abandoned,

            /// <summary>The mod is no longer needed and should be removed.</summary>
            Obsolete
        }

        // Based on SMAPI's ModExtendedMetadataModel.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
        /// <summary>The mod's display name.</summary>
        public string Name { get; set; }

        /// <summary>The main version.</summary>
        public ModEntryVersion Main { get; set; }

        /// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary>
        public ModEntryVersion Unofficial { get; set; }
        public string CustomUrl { get; set; }

        [JsonConverter(typeof(JsonStringEnumConverter))]
        public WikiCompatibilityStatus CompatibilityStatus { get; set; }

        /// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatting.</summary>
        public string CompatibilitySummary { get; set; }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Web/ModEntryVersion.cs
================================================
namespace Stardrop.Models.SMAPI.Web
{
    public class ModEntryVersion
    {
        // Based on SMAPI's ModEntryVersionModel.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs

        /*********
        ** Accessors
        *********/
        /// <summary>The version number.</summary>
        public string Version { get; set; }

        /// <summary>The mod page URL.</summary>
        public string Url { get; set; }


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance.</summary>
        public ModEntryVersion() { }

        /// <summary>Construct an instance.</summary>
        /// <param name="version">The version number.</param>
        /// <param name="url">The mod page URL.</param>
        public ModEntryVersion(string version, string url)
        {
            this.Version = version;
            this.Url = url;
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Web/ModSearchData.cs
================================================
using System.Collections.Generic;

namespace Stardrop.Models.SMAPI.Web
{
    class ModSearchData
    {
        // Based on SMAPI's ModSearchModel.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs

        /*********
        ** Accessors
        *********/
        /// <summary>The mods for which to find data.</summary>
        public ModSearchEntry[] Mods { get; set; }

        /// <summary>Whether to include extended metadata for each mod.</summary>
        public bool IncludeExtendedMetadata { get; set; }

        /// <summary>The SMAPI version installed by the player. This is used for version mapping in some cases.</summary>
        public string ApiVersion { get; set; }

        /// <summary>The Stardew Valley version installed by the player.</summary>
        public string GameVersion { get; set; }

        /// <summary>The OS on which the player plays.</summary>
        public string Platform { get; set; }


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an empty instance.</summary>
        public ModSearchData()
        {
            // needed for JSON deserializing
        }

        /// <summary>Construct an instance.</summary>
        /// <param name="mods">The mods to search.</param>
        /// <param name="apiVersion">The SMAPI version installed by the player. If this is null, the API won't provide a recommended update.</param>
        /// <param name="gameVersion">The Stardew Valley version installed by the player.</param>
        /// <param name="platform">The OS on which the player plays.</param>
        /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
        public ModSearchData(List<ModSearchEntry> mods, string apiVersion, string gameVersion, string platform, bool includeExtendedMetadata)
        {
            this.Mods = mods.ToArray();
            this.ApiVersion = apiVersion.ToString();
            this.GameVersion = gameVersion.ToString();
            this.Platform = platform;
            this.IncludeExtendedMetadata = includeExtendedMetadata;
        }
    }
}


================================================
FILE: Stardrop/Models/SMAPI/Web/ModSearchEntry.cs
================================================
using Semver;

namespace Stardrop.Models.SMAPI.Web
{
    public class ModSearchEntry
    {
        // Based on SMAPI's ModSearchEntryModel.cs: https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs

        /*********
        ** Accessors
        *********/
        /// <summary>The unique mod ID.</summary>
        public string Id { get; set; }

        /// <summary>The namespaced mod update keys (if available).</summary>
        public string[] UpdateKeys { get; set; }

        /// <summary>The mod version installed by the local player. This is used for version mapping in some cases.</summary>
        public string InstalledVersion { get; set; }


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an empty instance.</summary>
        public ModSearchEntry()
        {
            // needed for JSON deserializing
        }

        /// <summary>Construct an instance.</summary>
        /// <param name="id">The unique mod ID.</param>
        /// <param name="installedVersion">The version installed by the local player. This is used for version mapping in some cases.</param>
        /// <param name="updateKeys">The namespaced mod update keys (if available).</param>
        /// <param name="isBroken">Whether the installed version is broken or could not be loaded.</param>
        public ModSearchEntry(string id, SemVersion installedVersion, string[] updateKeys, bool isBroken = false)
        {
            this.Id = id;
            this.InstalledVersion = installedVersion.ToString();
            this.UpdateKeys = updateKeys ?? new string[0];
        }
    }
}


================================================
FILE: Stardrop/Models/Settings.cs
================================================
using Stardrop.Models.Data.Enums;
using Stardrop.Models.Nexus;
using Stardrop.Models.SMAPI;

namespace Stardrop.Models
{
    public class Settings
    {
        public string Theme { get; set; } = "Stardrop";
        public string Language { get; set; }
        public ModGrouping ModGroupingMethod { get; set; } = ModGrouping.None;
        public string Version { get; set; }
        public string LastSelectedProfileName { get; set; }
        public string SMAPIFolderPath { get; set; }
        public string ModFolderPath { get; set; }
        public string ModInstallPath { get; set; }
        public bool IgnoreHiddenFolders { get; set; } = true;
        public bool EnableProfileSpecificModConfigs { get; set; }
        public bool ShouldWriteToModConfigs { get; set; }
        public bool EnableModsOnAdd { get; set; }
        /// <summary>
        /// Whether to always ask before deleting a previous version of a mod when updating the mod.
        /// </summary>
        public bool AlwaysAskToDelete { get; set; } = true;
        public bool ShouldAutomaticallySaveProfileChanges { get; set; } = true;
        public bool ShowModThumbnails { get; set; }
        public NexusServers PreferredNexusServer { get; set; } = NexusServers.NexusCDN;
        public bool IsAskingBeforeAcceptingNXM { get; set; } = true;
        public GameDetails GameDetails { get; set; }
        public NexusUser NexusDetails { get; set; }

        public Settings ShallowCopy()
        {
            return (Settings)this.MemberwiseClone();
        }
    }
}


================================================
FILE: Stardrop/Models/Theme.cs
================================================
using Avalonia.Styling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stardrop.Models
{
    public class Theme
    {
        public required string Name { get; set; }
        public string? Author { get; set; }
        public bool IsEnabled { get; set; }

        public IStyle? Style { get; set; }
    }
}


================================================
FILE: Stardrop/Program.cs
================================================
using Avalonia;
using Avalonia.ReactiveUI;
using Avalonia.Shared.PlatformSupport;
using CommandLine;
using Projektanker.Icons.Avalonia;
using Projektanker.Icons.Avalonia.MaterialDesign;
using Semver;
using Stardrop.Models;
using Stardrop.Models.Nexus;
using Stardrop.Models.Nexus.Web;
using Stardrop.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;

namespace Stardrop
{
    class Program
    {
        internal static Helper helper;
        internal static Settings settings = new Settings();
        internal static Translation translation = new Translation();
        internal static AssetLoader assetLoader = new AssetLoader();

        internal static bool onBootStartSMAPI = false;
        internal static string? nxmLink = null;
        internal static readonly string defaultProfileName = "Default";
        internal static readonly string executablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Stardrop.exe");
        internal static readonly Regex gameDetailsPattern = new Regex(@"SMAPI (?<smapiVersion>.+) with Stardew Valley (?<gameVersion>.+) on (?<system>.+)");

        public static string ApplicationVersion { get { return $"{_applicationVersion.WithoutMetadata()}"; } }
        private static readonly SemVersion _applicationVersion = SemVersion.Parse(typeof(Program).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion, SemVersionStyles.Any);

        public class Options
        {
            [Option("start-smapi", Required = false, HelpText = "Automatically starts SMAPI based on the last selected mod profile.")]
            public bool StartSmapi { get; set; }
            [Option("nxm", Required = false, HelpText = "Downloads the given NXM file from Nexus Mods.")]
            public string? NXMLink { get; set; }
        }

        // Initialization code. Don't use any Avalonia, third-party APIs or any
        // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
        // yet and stuff might break.
        [STAThread]
        public static void Main(string[] args)
        {
            // Enforce the directory's path
            Directory.SetCurrentDirectory(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName));

            // Establish file and folders paths
            Pathing.SetHomePath(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

            // Verify if another instance is already running
            if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Count() > 1 && RuntimeInformation.IsOSPlatform(OSPlatform.OSX) is false)
            {
                helper = new Helper($"nxm", ".txt", Pathing.GetLogFolderPath());

                HandleSecondaryInstance(args);
                return;
            }

            // Set up our logger
            helper = new Helper("log", ".txt", Pathing.GetLogFolderPath());

            try
            {
                var operatingSystem = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "Windows" : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "Unix" : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "macOS" : "Unknown";
                helper.Log($"{Environment.NewLine}-- Startup Data --{Environment.NewLine}Time: {DateTime.Now}{Environment.NewLine}OS: [{operatingSystem}] {RuntimeInformation.OSDescription}{Environment.NewLine}Settings Directory: {Pathing.defaultHomePath}{Environment.NewLine}Active Directory: {Directory.GetCurrentDirectory()}{Environment.NewLine}Version: v{ApplicationVersion}{Environment.NewLine}----------------------{Environment.NewLine}");
                helper.Log($"Started with the following arguments: {String.Join('|', args)}");

                // Set the argument values
                Parser.Default.ParseArguments<Options>(args).WithParsed<Options>(o =>
                {
                    onBootStartSMAPI = o.StartSmapi;
                    nxmLink = o.NXMLink;
                });

                // Verify the folder paths are created
                Directory.CreateDirectory(Pathing.GetCacheFolderPath());
                Directory.CreateDirectory(Pathing.GetLogFolderPath());
                Directory.CreateDirectory(Pathing.GetProfilesFolderPath());
                Directory.CreateDirectory(Pathing.GetSelectedModsFolderPath());
                Directory.CreateDirectory(Pathing.GetNexusPath());
                Directory.CreateDirectory(Pathing.GetThumbnailsPath());
                Directory.CreateDirectory(Pathing.GetSmapiUpgradeFolderPath());

                // Verify the settings folder path is created
                if (File.Exists(Pathing.GetSettingsPath()))
                {
                    try
                    {
                        settings = JsonSerializer.Deserialize<Settings>(File.ReadAllText(Pathing.GetSettingsPath()), new JsonSerializerOptions { AllowTrailingCommas = true });
                    }
                    catch (JsonException ex)
                    {
                        settings = new Settings();
                        helper.Log($"Reset the settings.json file as it was unreadable: {ex}", Helper.Status.Alert);
                    }
                }

                // Set the default paths
                if (!String.IsNullOrEmpty(settings.ModFolderPath))
                {
                    Pathing.SetSmapiPath(settings.SMAPIFolderPath);
                    Pathing.SetModPath(settings.ModFolderPath);
                }
                else
                {
                    Pathing.SetSmapiPath(settings.SMAPIFolderPath, true);
                    settings.ModFolderPath = Pathing.defaultModPath;
                }

                // Set the default mod install path (for mods that are installed by Stardrop)
                if (!String.IsNullOrEmpty(Pathing.defaultModPath) && String.IsNullOrEmpty(settings.ModInstallPath))
                {
                    settings.ModInstallPath = Path.Combine(Pathing.defaultModPath, "Stardrop Installed Mods");
                }

                // Set the default Nexus Mods information
                if (settings.NexusDetails is null)
                {
                    settings.NexusDetails = new NexusUser();
                }

                // Delete any files underneath the Nexus folder
                var nexusDirectory = new DirectoryInfo(Pathing.GetNexusPath());
                foreach (FileInfo file in nexusDirectory.GetFiles())
                {
                    file.Delete();
                }
                foreach (DirectoryInfo dir in nexusDirectory.GetDirectories())
                {
                    dir.Delete(true);
                }

                // Load the translations
                if (String.IsNullOrEmpty(settings.Language))
                {
                    settings.Language = translation.GetLanguageFromAbbreviation(CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
                }
                translation.LoadTranslations(translation.GetLanguage(settings.Language));

                BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
            }
            catch (Exception ex)
            {
                helper.Log(ex, Helper.Status.Alert);
            }
        }

        private static void HandleSecondaryInstance(string[] args)
        {
            Parser.Default.ParseArguments<Options>(args).WithParsed<Options>(o =>
            {
                nxmLink = o.NXMLink;
            });

            // Verify NXM link is valid
            if (String.IsNullOrEmpty(nxmLink))
            {
                Program.helper.Log("Given empty NXM link");
                return;
            }

            // Write to bridge file
            int attempts = 0;

            Program.helper.Log("STARTING");
            while (true)
            {
                try
                {
                    using (FileStream stream = new FileStream(Pathing.GetLinksCachePath(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                    {
                        List<NXM> links;
                        try
                        {
                            links = JsonSerializer.DeserializeAsync<List<NXM>>(stream, new JsonSerializerOptions { AllowTrailingCommas = true }).Result;

                            if (links is null)
                            {
                                links = new List<NXM>();
                            }
                        }
                        catch (JsonException ex)
                        {
                            links = new List<NXM>();
                        }

                        try
                        {
                            links.Add(new NXM() { Link = nxmLink, Timestamp = DateTime.Now });
                            Program.helper.Log(links.Count());

                            stream.SetLength(0);

                            JsonSerializer.SerializeAsync(stream, links, new JsonSerializerOptions() { WriteIndented = true });

                            break;
                        }
                        catch (Exception ex)
                        {
                            Program.helper.Log(ex);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Program.helper.Log(ex);
                }

                if (attempts >= 3)
                {
                    return;
                }
                else
                {
                    attempts += 1;
                    Thread.Sleep(500);
                }
            }

            Program.helper.Log("DONE");
        }

        // Avalonia configuration, don't remove; also used by visual designer.
        public static AppBuilder BuildAvaloniaApp()
        {
            return AppBuilder.Configure<App>()
                .UseReactiveUI()
                .UsePlatformDetect()
                .LogToTrace()
                .WithIcons(container => container
                .Register<MaterialDesignIconProvider>());
        }
    }
}


================================================
FILE: Stardrop/Properties/PublishProfiles/FolderProfile - Linux.pubxml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration>Release</Configuration>
    <Platform>Any CPU</Platform>
    <PublishDir>publish\linux</PublishDir>
    <PublishProtocol>FileSystem</PublishProtocol>
    <TargetFramework>net7.0</TargetFramework>
    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
    <SelfContained>true</SelfContained>
    <PublishSingleFile>true</PublishSingleFile>
  </PropertyGroup>
</Project>

================================================
FILE: Stardrop/Properties/PublishProfiles/FolderProfile - MacOS.pubxml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration>Release</Configuration>
    <Platform>Any CPU</Platform>
    <PublishDir>publish\mac</PublishDir>
    <PublishProtocol>FileSystem</PublishProtocol>
    <TargetFramework>net7.0</TargetFramework>
    <RuntimeIdentifier>osx-x64</RuntimeIdentifier>
    <SelfContained>true</SelfContained>
    <PublishSingleFile>true</PublishSingleFile>
  </PropertyGroup>
</Project>

================================================
FILE: Stardrop/Properties/PublishProfiles/FolderProfile - Windows.pubxml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration>Release</Configuration>
    <Platform>Any CPU</Platform>
    <PublishDir>publish\windows</PublishDir>
    <PublishProtocol>FileSystem</PublishProtocol>
    <TargetFramework>net7.0</TargetFramework>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <SelfContained>true</SelfContained>
    <PublishSingleFile>true</PublishSingleFile>
    <PublishReadyToRun>false</PublishReadyToRun>
  </PropertyGroup>
</Project>

================================================
FILE: Stardrop/Stardrop.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>WinExe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<Nullable>enable</Nullable>
		<Version>1.8.4-beta.2</Version>
		<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
		<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
		<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
	</PropertyGroup>
	<PropertyGroup>
		<PublishSingleFile>true</PublishSingleFile>
		<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
	</PropertyGroup>
	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
		<OutputPath></OutputPath>
		<PlatformTarget>x64</PlatformTarget>
	</PropertyGroup>
	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
		<PlatformTarget>x64</PlatformTarget>
	</PropertyGroup>
	<ItemGroup>
		<AvaloniaResource Include="Assets\**" />
		<Content Include="Themes\**" CopyToOutputDirectory="PreserveNewest" />
		<Content Include="i18n\*" CopyToOutputDirectory="PreserveNewest" />
		<None Remove=".gitignore" />
		<None Remove="Assets\icon.ico" />
		<None Remove="Assets\Info.plist" />
		<None Remove="Assets\smapi.png" />
		<None Remove="Assets\Stardrop.icns" />
		<None Remove="Assets\Stardrop.sh" />
		<None Remove="Themes\Dark.xaml" />
		<None Remove="Themes\Light.xaml" />
		<None Remove="Themes\Solarized-Lite.xaml" />
	</ItemGroup>
	<ItemGroup>
	  <Content Include="Themes\Contributors\hotcereal\CASH MONEY.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Cerene Dark.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Cerene Light.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Dark Cherry Chocolate.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Fairy.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Forest.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Light %28Pink%29.xaml" />
	  <Content Include="Themes\Contributors\hotcereal\Light Cherry Chocolate.xaml" />
	</ItemGroup>
	<ItemGroup>
		<PackageReference Include="Avalonia" Version="0.10.22" />
		<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.22" />
		<PackageReference Include="Avalonia.Desktop" Version="0.10.22" />
		<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
		<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.22" />
		<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.22" />
		<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.22" />
		<PackageReference Include="CommandLineParser" Version="2.9.1" />
		<PackageReference Include="Json.More.Net" Version="2.0.1" />
		<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
		<PackageReference Include="Projektanker.Icons.Avalonia" Version="5.13.0" />
		<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="5.13.0" />
		<PackageReference Include="semver" Version="2.3.0" />
		<PackageReference Include="SharpCompress" Version="0.32.1" />
	</ItemGroup>
	<ItemGroup>
		<Compile Update="Views\FlexibleOptionWindow.axaml.cs">
			<DependentUpon>FlexibleOptionWindow.axaml</DependentUpon>
		</Compile>
		<Compile Update="Views\NexusInfo.axaml.cs">
			<DependentUpon>NexusInfo.axaml</DependentUpon>
		</Compile>
		<Compile Update="Views\ProfileNaming.axaml.cs">
			<DependentUpon>ProfileNaming.axaml</DependentUpon>
		</Compile>
		<Compile Update="Views\ProfileEditor.axaml.cs">
			<DependentUpon>ProfileEditor.axaml</DependentUpon>
		</Compile>
		<Compile Update="Views\WarningWindow.axaml.cs">
			<DependentUpon>WarningWindow.axaml</DependentUpon>
		</Compile>
        <Compile Update="Views\DownloadPanel.axaml.cs">
            <DependentUpon>DownloadPanel.axaml</DependentUpon>
        </Compile>
	</ItemGroup>
	<ItemGroup>
		<Content Update="Themes\Light.xaml">
			<SubType>Designer</SubType>
			<Generator>MSBuild:Compile</Generator>
		</Content>
		<Content Update="Themes\Solarized-Lite.xaml">
			<SubType>Designer</SubType>
			<Generator>MSBuild:Compile</Generator>
		</Content>
		<Content Update="Themes\Dark.xaml">
			<SubType>Designer</SubType>
			<Generator>MSBuild:Compile</Generator>
		</Content>
		<Content Update="Themes\Stardrop.xaml">
			<Generator>MSBuild:Compile</Generator>
		</Content>
	</ItemGroup>
</Project>


================================================
FILE: Stardrop/Stardrop.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31729.503
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stardrop", "Stardrop.csproj", "{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {86B7436F-BA81-4F86-B816-DB4AD0E2C918}
	EndGlobalSection
EndGlobal


================================================
FILE: Stardrop/Themes/Contributors/hotcereal/CASH MONEY.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Styles.Resources>

        <!-- Base Colors -->
        <Color x:Key="GreenBg">#4FA57E</Color>
        <Color x:Key="GreenRow">#6AB892</Color>
        <Color x:Key="GreenRowAlt">#74C29B</Color>
        <Color x:Key="GreenText">#0F241C</Color>

        <!-- Accent / UI Colors -->
        <Color x:Key="SelectedGreen">#C6E0D3</Color>
        <Color x:Key="MintHover">#8AD3AF</Color>
        <Color x:Key="StemBorder">#3E7F62</Color>
        <Color x:Key="DeepGreen">#2E5F4B</Color>

        <Color x:Key="SystemAccentColor">#6AB892</Color>

        <!-- Avalonia Brushes -->
        <SolidColorBrush x:Key="ThemeBackgroundBrush"
                         Color="{DynamicResource GreenBg}" />
        <SolidColorBrush x:Key="ThemeForegroundBrush"
                         Color="{DynamicResource GreenText}" />
        <SolidColorBrush x:Key="ThemeControlMidBrush"
                         Color="{DynamicResource GreenRowAlt}" />
        <SolidColorBrush x:Key="ThemeControlHighBrush"
                         Color="{DynamicResource GreenText}"
                         Opacity="0.65" />
        <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                         Color="{DynamicResource GreenText}"
                         Opacity="0.6" />
        <SolidColorBrush x:Key="HighlightBrush"
                         Color="{DynamicResource StemBorder}" />
        <SolidColorBrush x:Key="HighlightForegroundBrush"
                         Color="{DynamicResource GreenText}" />

    </Styles.Resources>

    <!-- DataGrid -->
    <Style Selector="DataGrid">
        <Setter Property="Background" Value="{DynamicResource GreenBg}" />
        <Setter Property="BorderBrush" Value="{DynamicResource StemBorder}" />
        <Setter Property="Foreground" Value="{DynamicResource GreenText}" />
    </Style>

    <Style Selector="DataGridRow">
        <Setter Property="Background" Value="{DynamicResource GreenRow}" />
        <Setter Property="Foreground" Value="{DynamicResource GreenText}" />
    </Style>

    <Style Selector="DataGridRow:nth-child(even)">
        <Setter Property="Background" Value="{DynamicResource GreenRowAlt}" />
    </Style>

    <Style Selector="DataGridRow:selected">
        <Setter Property="Background" Value="{DynamicResource SelectedGreen}" />
        <Setter Property="Foreground" Value="{DynamicResource GreenText}" />
    </Style>

    <Style Selector="DataGridRow:pointerover">
        <Setter Property="Background" Value="{DynamicResource MintHover}" />
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Cerene Dark.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Base Colors -->
            <Color x:Key="NightBlack">#2B313C</Color>        <!-- Main background -->
            <Color x:Key="OffBlack">#343B48</Color>          <!-- Panels / rows -->
            <Color x:Key="DarkestGray">#252A34</Color>       <!-- Deep background -->
            <Color x:Key="DarkGray">#3A4252</Color>          <!-- Headers -->
            <Color x:Key="OffGray">#40485A</Color>           <!-- Alt rows -->
            <Color x:Key="PerfectGray">#5E677A</Color>       <!-- Subtle borders -->
            <Color x:Key="White">#E6E9EF</Color>             <!-- Primary text -->

            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#8FD4A1</Color>          <!-- Enabled checkmarks -->
            <Color x:Key="CalmBlue">#6FA8DC</Color>          <!-- Highlights -->
            <Color x:Key="NeonRed">#D96C6C</Color>           <!-- Errors -->
            <Color x:Key="NeonYellow">#D7D18B</Color>        <!-- Warnings -->
            <Color x:Key="GrayBlue">#6FA3B8</Color>          <!-- Links / focus -->
            <Color x:Key="DarkPurple">#3B3F5C</Color>        <!-- Rare accents -->

            <!-- Avalonia Brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush" Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush" Color="{DynamicResource White}" Opacity="0.25" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource White}" Opacity="0.65" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush" Color="{DynamicResource White}" Opacity="0.75" />
            <SolidColorBrush x:Key="ThemeAccentBrush" Color="{DynamicResource White}" Opacity="0.2" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource White}" Opacity="0.35" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground" Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground" Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground" Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush" Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush" Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush" Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Cerene Light.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Styles.Resources>

        <!-- Base Colors -->
        <Color x:Key="IceBg">#F6FAFF</Color>
        <Color x:Key="IceRow">#EEF3FF</Color>
        <Color x:Key="IceRowAlt">#E6EDFF</Color>
        <Color x:Key="IceText">#1E2433</Color>

        <!-- Accent / UI Colors -->
        <Color x:Key="RRed">#FF5F5F</Color>
        <Color x:Key="ROrange">#FF9F43</Color>
        <Color x:Key="RYellow">#FFD93D</Color>
        <Color x:Key="RGreen">#4EDEA3</Color>
        <Color x:Key="RCyan">#3FD9FF</Color>
        <Color x:Key="RBlue">#5C7CFA</Color>
        <Color x:Key="RPurple">#B197FC</Color>

        <!-- Avalonia Brushes -->
        <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource IceBg}" />
        <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource IceText}" />
        <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource IceRowAlt}" />
        <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource IceText}" Opacity="0.65" />
        <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource IceText}" Opacity="0.6" />
        
        <!-- Need to look into why missing a SolidColorBrush causes Stardrop to not display them in styles -->
        <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource LightGray}" />
    </Styles.Resources>

    <!-- DataGrid -->
    <Style Selector="DataGrid">
        <Setter Property="Background" Value="{DynamicResource IceBg}" />
        <Setter Property="BorderBrush" Value="{DynamicResource RCyan}" />
        <Setter Property="Foreground" Value="{DynamicResource IceText}" />
    </Style>

    <Style Selector="DataGridRow">
        <Setter Property="Background" Value="{DynamicResource IceRow}" />
        <Setter Property="Foreground" Value="{DynamicResource IceText}" />
    </Style>

    <Style Selector="DataGridRow:nth-child(even)">
        <Setter Property="Background" Value="{DynamicResource IceRowAlt}" />
    </Style>

    <Style Selector="DataGridRow:selected">
        <Setter Property="Background">
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                <GradientStop Color="{DynamicResource RRed}" Offset="0.0" />
                <GradientStop Color="{DynamicResource ROrange}" Offset="0.16" />
                <GradientStop Color="{DynamicResource RYellow}" Offset="0.33" />
                <GradientStop Color="{DynamicResource RGreen}" Offset="0.5" />
                <GradientStop Color="{DynamicResource RCyan}" Offset="0.66" />
                <GradientStop Color="{DynamicResource RBlue}" Offset="0.83" />
                <GradientStop Color="{DynamicResource RPurple}" Offset="1.0" />
            </LinearGradientBrush>
        </Setter>
        <Setter Property="Foreground" Value="{DynamicResource IceText}" />
    </Style>

    <Style Selector="DataGridRow:pointerover">
        <Setter Property="Background">
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0" Opacity="0.4">
                <GradientStop Color="{DynamicResource RCyan}" Offset="0.0" />
                <GradientStop Color="{DynamicResource RBlue}" Offset="1.0" />
            </LinearGradientBrush>
        </Setter>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Dark Cherry Chocolate.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Base Colors -->
            <Color x:Key="NightBlack">#2E2326</Color>
            <Color x:Key="OffBlack">#3A2B30</Color>
            <Color x:Key="DarkestGray">#24191D</Color>
            <Color x:Key="DarkGray">#46323A</Color>
            <Color x:Key="OffGray">#4A353D</Color>
            <Color x:Key="PerfectGray">#6E5860</Color>
            <Color x:Key="White">#EFE6EA</Color>

            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#CFA3B4</Color>
            <Color x:Key="CalmBlue">#B57A8C</Color>
            <Color x:Key="NeonRed">#C96C7D</Color>
            <Color x:Key="NeonYellow">#D6B3A2</Color>
            <Color x:Key="GrayBlue">#C08FA0</Color>
            <Color x:Key="DarkPurple">#3B2A30</Color>

            <!-- Avalonia Brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush"
                             Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush"
                             Color="{DynamicResource White}" />

            <SolidColorBrush x:Key="HighlightBrush"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush"
                             Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush"
                             Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.25" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush"
                             Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.65" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.75" />
            <SolidColorBrush x:Key="ThemeAccentBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.2" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.35" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground"
                             Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground"
                             Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush"
                             Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush"
                             Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush"
                             Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush"
                             Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Fairy.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Base Colors -->
            <Color x:Key="NightBlack">#F6ECEF</Color>
            <Color x:Key="OffBlack">#EFE3E8</Color>
            <Color x:Key="DarkestGray">#E5D7DD</Color>
            <Color x:Key="DarkGray">#DDD0D6</Color>
            <Color x:Key="OffGray">#F8EEF2</Color>
            <Color x:Key="PerfectGray">#C8B8BF</Color>
            <Color x:Key="White">#3A2A31</Color>

            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#E8B8C9</Color>
            <Color x:Key="CalmBlue">#F0B4CB</Color>
            <Color x:Key="NeonRed">#D98AA4</Color>
            <Color x:Key="NeonYellow">#EAD3C6</Color>
            <Color x:Key="GrayBlue">#F3C9D9</Color>
            <Color x:Key="DarkPurple">#8A6675</Color>

            <!-- Avalonia Brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush"
                             Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush"
                             Color="{DynamicResource White}" />

            <SolidColorBrush x:Key="HighlightBrush"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush"
                             Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush"
                             Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.18" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush"
                             Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.6" />
            <SolidColorBrush x:Key="ThemeAccentBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.12" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.65" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground"
                             Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground"
                             Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush"
                             Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush"
                             Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush"
                             Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush"
                             Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Forest.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Base Colors -->
            <Color x:Key="NightBlack">#2B2118</Color>
            <Color x:Key="OffBlack">#33271D</Color>
            <Color x:Key="DarkestGray">#241B14</Color>
            <Color x:Key="DarkGray">#3B2E23</Color>
            <Color x:Key="OffGray">#413327</Color>
            <Color x:Key="PerfectGray">#6A5B4C</Color>
            <Color x:Key="White">#E6E2DD</Color>

            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#8FBFA3</Color>
            <Color x:Key="CalmBlue">#6F9E86</Color>
            <Color x:Key="NeonRed">#C97A6A</Color>
            <Color x:Key="NeonYellow">#CBBF87</Color>
            <Color x:Key="GrayBlue">#7FAF95</Color>
            <Color x:Key="DarkPurple">#3E352C</Color>

            <!-- Avalonia Brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush"
                             Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush"
                             Color="{DynamicResource White}" />

            <SolidColorBrush x:Key="HighlightBrush"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush"
                             Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush"
                             Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush"
                             Color="{DynamicResource White}" Opacity="0.25" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush"
                             Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush"
                             Color="{DynamicResource White}" Opacity="0.65" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush"
                             Color="{DynamicResource White}" Opacity="0.75" />
            <SolidColorBrush x:Key="ThemeAccentBrush"
                             Color="{DynamicResource White}" Opacity="0.2" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                             Color="{DynamicResource White}" Opacity="0.35" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground"
                             Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground"
                             Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush"
                             Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush"
                             Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush"
                             Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush"
                             Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Light (Pink).xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Base Colors -->
            <Color x:Key="NightBlack">#FAF3F6</Color>
            <Color x:Key="OffBlack">#F2E6EB</Color>
            <Color x:Key="DarkestGray">#E8D8DE</Color>
            <Color x:Key="DarkGray">#DEC9D2</Color>
            <Color x:Key="OffGray">#F8EFF3</Color>
            <Color x:Key="PerfectGray">#C9B5BE</Color>
            <Color x:Key="White">#3B2A31</Color>

            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#E9B9C9</Color>
            <Color x:Key="CalmBlue">#F1B6CD</Color>
            <Color x:Key="NeonRed">#DB8FA6</Color>
            <Color x:Key="NeonYellow">#ECD6C9</Color>
            <Color x:Key="GrayBlue">#F4CEDC</Color>
            <Color x:Key="DarkPurple">#8E6A78</Color>

            <!-- Avalonia Brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush"
                             Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush"
                             Color="{DynamicResource White}" />

            <SolidColorBrush x:Key="HighlightBrush"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush"
                             Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush"
                             Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.18" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush"
                             Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.6" />
            <SolidColorBrush x:Key="ThemeAccentBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.12" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.65" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground"
                             Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground"
                             Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush"
                             Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush"
                             Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush"
                             Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush"
                             Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Contributors/hotcereal/Light Cherry Chocolate.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

        <!-- Base Colors -->
            <Color x:Key="NightBlack">#3A2F34</Color>        
            <Color x:Key="OffBlack">#4A3A41</Color>          
            <Color x:Key="DarkestGray">#2F2428</Color>       
            <Color x:Key="DarkGray">#5A454D</Color>          
            <Color x:Key="OffGray">#5F4850</Color>           
            <Color x:Key="PerfectGray">#8A717B</Color>       
            <Color x:Key="White">#F6EDF1</Color>             

 
            <!-- Accent / UI Colors -->
            <Color x:Key="NeonMint">#D8A8BC</Color>
            <Color x:Key="CalmBlue">#E2A3BE</Color>          
            <Color x:Key="NeonRed">#E08AA2</Color>
            <Color x:Key="NeonYellow">#E8C6B8</Color>
            <Color x:Key="GrayBlue">#E6B4C8</Color>
            <Color x:Key="DarkPurple">#4A343C</Color>

            <!-- Avalonia brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush"
                             Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush"
                             Color="{DynamicResource White}" />

            <!-- Selection behavior preserved -->
            <SolidColorBrush x:Key="HighlightBrush"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush"
                             Color="{DynamicResource CalmBlue}" />

            <SolidColorBrush x:Key="ThemeControlMidBrush"
                             Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.25" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush"
                             Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.65" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.75" />
            <SolidColorBrush x:Key="ThemeAccentBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.2" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush"
                             Color="{DynamicResource White}"
                             Opacity="0.35" />

            <!-- DataGrid -->
            <SolidColorBrush x:Key="DataGridHeaderBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground"
                             Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground"
                             Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground"
                             Color="{DynamicResource White}" />

            <!-- ComboBox -->
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush"
                             Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush"
                             Color="{DynamicResource GrayBlue}" />

            <!-- Status -->
            <SolidColorBrush x:Key="UpdateAvailableBrush"
                             Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush"
                             Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush"
                             Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Dark.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">
    <Style>
        <Style.Resources>

            <!-- Colors -->
            <Color x:Key="NeonOrange">#ff9f2a</Color>
            <Color x:Key="OffBlack">#424242</Color>
            <Color x:Key="NightBlack">#1b1b1b</Color>
            <Color x:Key="NeonMint">#1cff96</Color>
            <Color x:Key="NeonRed">#f74040</Color>
            <Color x:Key="NeonYellow">#fdfd2e</Color>
            <Color x:Key="DarkPurple">#2a0a84</Color>
            <Color x:Key="DarkGray">#2E2E2E</Color>
            <Color x:Key="GrayBlue">#3abcbc</Color>
            <Color x:Key="PerfectGray">#6B6B6B</Color>
            <Color x:Key="OffGray">#525252</Color>
            <Color x:Key="DarkestGray">#2a2824</Color>
            <Color x:Key="White">#ffffff</Color>


            <!-- Avalonia brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource NightBlack}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource NeonMint}"/>
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource OffBlack}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush" Color="{DynamicResource NeonOrange}"/>
            <SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource OrangeColor}" />
            <SolidColorBrush x:Key="ThemeAccentBrush3" Color="{DynamicResource BrightOrangeColor}" />
            <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeBorderMidBrush" Color="{DynamicResource BlackColor}"
                   Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeAccentBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ErrorBrush" Color="{DynamicResource ErrorColor}" />

            <!-- Custom brushes -->
            <SolidColorBrush x:Key="DataGridHeaderBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground" Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateAvailableBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush" Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush" Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Light.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">

    <Style>
        <Style.Resources>

            <!-- Colors -->
            <Color x:Key="LightGray">#a69b97</Color>
            <Color x:Key="NeonOrange">#ff9f2a</Color>
            <Color x:Key="DarkSeaBlue">#031332</Color>
            <Color x:Key="NeonMint">#389538</Color>
            <Color x:Key="NeonRed">#ff0000</Color>
            <Color x:Key="NeonYellow">#ffc107</Color>
            <Color x:Key="DarkPurple">#2a0a84</Color>
            <Color x:Key="DarkGray">#bdb9b7</Color>
            <Color x:Key="GrayBlue">#3abcbc</Color>
            <Color x:Key="PerfectGray">#e0e0e0</Color>
            <Color x:Key="OffGray">#c2c2c2</Color>
            <Color x:Key="MiddleGray">#8c8c8c</Color>
            <Color x:Key="DarkestGray">#2a2824</Color>
            <Color x:Key="White">#efebe9</Color>


            <!-- Avalonia brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource DarkestGray}"/>
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource LightGray}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush" Color="{DynamicResource NeonOrange}"/>
            <SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource OrangeColor}" />
            <SolidColorBrush x:Key="ThemeAccentBrush3" Color="{DynamicResource BrightOrangeColor}" />
            <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush" Color="{DynamicResource DarkestGray}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeBorderMidBrush" Color="{DynamicResource BlackColor}"
                   Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeAccentBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ErrorBrush" Color="{DynamicResource ErrorColor}" />

            <!-- Custom brushes -->
            <SolidColorBrush x:Key="DataGridHeaderBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground" Color="{DynamicResource DarkestGray}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="UpdateAvailableBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush" Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush" Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Solarized-Lite.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">
    <Style>
        <Style.Resources>

            <!-- Colors -->
            <Color x:Key="NeonOrange">#ff9f2a</Color>
            <Color x:Key="DarkSeaBlue">#031332</Color>
            <Color x:Key="NeonMint">#1cff96</Color>
            <Color x:Key="NeonRed">#f74040</Color>
            <Color x:Key="NeonYellow">#fdfd2e</Color>
            <Color x:Key="DarkPurple">#2a0a84</Color>
            <Color x:Key="DarkGray">#2E2E2E</Color>
            <Color x:Key="GrayBlue">#3abcbc</Color>
            <Color x:Key="PerfectGray">#6B6B6B</Color>
            <Color x:Key="OffGray">#525252</Color>
            <Color x:Key="DarkestGray">#2a2824</Color>
            <Color x:Key="White">#ffffff</Color>


            <!-- Avalonia brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource NeonMint}"/>
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource NeonOrange}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush" Color="{DynamicResource NeonOrange}"/>
            <SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource OrangeColor}" />
            <SolidColorBrush x:Key="ThemeAccentBrush3" Color="{DynamicResource BrightOrangeColor}" />
            <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeBorderMidBrush" Color="{DynamicResource BlackColor}"
                   Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeAccentBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ErrorBrush" Color="{DynamicResource ErrorColor}" />

            <!-- Custom brushes -->
            <SolidColorBrush x:Key="DataGridHeaderBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground" Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateAvailableBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush" Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush" Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Themes/Stardrop.xaml
================================================
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime">
    <Style>
        <Style.Resources>

            <!-- Colors -->
            <Color x:Key="NeonOrange">#ff9f2a</Color>
            <Color x:Key="DarkSeaBlue">#031332</Color>
            <Color x:Key="NeonMint">#1cff96</Color>
            <Color x:Key="NeonRed">#f74040</Color>
            <Color x:Key="NeonYellow">#fdfd2e</Color>
            <Color x:Key="DarkPurple">#2a0a84</Color>
            <Color x:Key="DarkGray">#2E2E2E</Color>
            <Color x:Key="GrayBlue">#3abcbc</Color>
            <Color x:Key="PerfectGray">#6B6B6B</Color>
            <Color x:Key="OffGray">#525252</Color>
            <Color x:Key="DarkestGray">#2a2824</Color>
            <Color x:Key="White">#ffffff</Color>


            <!-- Avalonia brushes -->
            <SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource DarkSeaBlue}" />
            <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource NeonMint}"/>
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource NeonOrange}" />
            <SolidColorBrush x:Key="HighlightForegroundBrush" Color="{DynamicResource NeonOrange}"/>
            <SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource OrangeColor}" />
            <SolidColorBrush x:Key="ThemeAccentBrush3" Color="{DynamicResource BrightOrangeColor}" />
            <SolidColorBrush x:Key="ThemeControlMidBrush" Color="{DynamicResource GrayBlue}" />
            <SolidColorBrush x:Key="ThemeControlMidHighBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundHighBrush" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="ThemeControlHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeControlVeryHighBrush" Color="{DynamicResource White}"
                   Opacity="0.7" />
            <SolidColorBrush x:Key="ThemeBorderMidBrush" Color="{DynamicResource BlackColor}"
                   Opacity="0.4" />
            <SolidColorBrush x:Key="ThemeAccentBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ThemeForegroundLowBrush" Color="{DynamicResource White}"
                   Opacity="0.3" />
            <SolidColorBrush x:Key="ErrorBrush" Color="{DynamicResource ErrorColor}" />

            <!-- Custom brushes -->
            <SolidColorBrush x:Key="DataGridHeaderBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="DataGridRowBackground" Color="{DynamicResource PerfectGray}" />
            <SolidColorBrush x:Key="DataGridRowForeground" Color="{DynamicResource White}" />
            <SolidColorBrush x:Key="AlternativeDataGridRowBackground" Color="{DynamicResource OffGray}" />
            <SolidColorBrush x:Key="ComboBoxItemBackgroundBrush" Color="{DynamicResource DarkGray}" />
            <SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundBrush" Color="{DynamicResource GrayBlue}" />
            <SolidColorBrush x:Key="UpdateAvailableBrush" Color="{DynamicResource NeonMint}" />
            <SolidColorBrush x:Key="UpdateBrokenBrush" Color="{DynamicResource NeonRed}" />
            <SolidColorBrush x:Key="UpdateUnofficialBrush" Color="{DynamicResource NeonYellow}" />

        </Style.Resources>
    </Style>

</Styles>

================================================
FILE: Stardrop/Utilities/Extension/TranslateExtension.cs
================================================
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using System;


namespace Stardrop.Utilities.Extension
{
    public class TranslateExtension : MarkupExtension
    {
        public TranslateExtension(string key)
        {
            this.Key = key;
        }

        public string Key { get; set; }

        public string Context { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var keyToUse = Key;
            if (!string.IsNullOrWhiteSpace(Context))
            {
                keyToUse = $"{Context}/{Key}";
            }

            var binding = new ReflectionBindingExtension($"[{keyToUse}]")
            {
                Mode = BindingMode.OneWay,
                Source = Program.translation,
            };

            return binding.ProvideValue(serviceProvider);
        }
    }
}


================================================
FILE: Stardrop/Utilities/External/GitHub.cs
================================================
using SharpCompress.Archives;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;

namespace Stardrop.Utilities.External
{
    static class GitHub
    {
        public async static Task<KeyValuePair<string, string>?> GetLatestSMAPIRelease()
        {
            KeyValuePair<string, string>? versionToUri = null;

            // Create a throwaway client
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("User-Agent", "Stardrop - SDV Mod Manager");

            try
            {
                var response = await client.GetAsync("https://api.github.com/repos/Pathoschild/SMAPI/releases/latest");

                if (response.Content is not null)
                {
                    JsonDocument parsedContent = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
                    string tagName = parsedContent.RootElement.GetProperty("tag_name").ToString();
                    string downloadUri = parsedContent.RootElement.GetProperty("html_url").ToString();
                    downloadUri = String.Concat(downloadUri, "/", $"SMAPI-{tagName}-installer.zip").Replace("releases/tag/", "releases/download/");

                    versionToUri = new KeyValuePair<string, string>(tagName, downloadUri);
                }
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to get latest the version of SMAPI: {ex}", Helper.Status.Alert);
            }
            client.Dispose();

            return versionToUri;
        }

        public async static Task<string> DownloadLatestSMAPIRelease(string uri)
        {
            // Create a throwaway client
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("User-Agent", "Stardrop - SDV Mod Manager");

            string downloadedArchivePath = String.Empty;
            try
            {
                var response = await client.GetAsync(uri);
                using (var archive = ArchiveFactory.Open(await response.Content.ReadAsStreamAsync()))
                {
                    downloadedArchivePath = Path.Combine(Pathing.GetSmapiUpgradeFolderPath(), Path.GetDirectoryName(archive.Entries.First().Key));
                    foreach (var entry in archive.Entries)
                    {
                        entry.WriteToDirectory(Pathing.GetSmapiUpgradeFolderPath(), new SharpCompress.Common.ExtractionOptions() { ExtractFullPath = true, Overwrite = true });
                    }
                }
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to download latest the version of SMAPI: {ex}", Helper.Status.Alert);
            }
            client.Dispose();

            return downloadedArchivePath;
        }

        public async static Task<KeyValuePair<string, string>?> GetLatestStardropRelease()
        {
            KeyValuePair<string, string>? versionToUri = null;

            // Create a throwaway client
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("User-Agent", "Stardrop - SDV Mod Manager");

            try
            {
                var response = await client.GetAsync("https://api.github.com/repos/Floogen/Stardrop/releases/latest");

                if (response.Content is not null)
                {
                    JsonDocument parsedContent = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
                    string tagName = parsedContent.RootElement.GetProperty("tag_name").ToString();
                    string downloadUri = parsedContent.RootElement.GetProperty("html_url").ToString();
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                    {
                        downloadUri = String.Concat(downloadUri, "/", "Stardrop-osx-x64.zip");
                    }
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        downloadUri = String.Concat(downloadUri, "/", "Stardrop-linux-x64.zip");
                    }
                    else
                    {
                        downloadUri = String.Concat(downloadUri, "/", "Stardrop-win-x64.zip");
                    }
                    downloadUri = downloadUri.Replace("releases/tag/", "releases/download/");

                    versionToUri = new KeyValuePair<string, string>(tagName, downloadUri);
                }
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to get latest the version of Stardrop: {ex}", Helper.Status.Alert);
            }
            client.Dispose();

            return versionToUri;
        }

        public async static Task<string> DownloadLatestStardropRelease(string uri)
        {
            // Create a throwaway client
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("User-Agent", "Stardrop - SDV Mod Manager");

            string downloadedArchivePath = String.Empty;
            try
            {
                var response = await client.GetAsync(uri);
                using (var archive = ArchiveFactory.Open(await response.Content.ReadAsStreamAsync()))
                {
                    foreach (var entry in archive.Entries)
                    {
                        entry.WriteToDirectory(Directory.GetCurrentDirectory(), new SharpCompress.Common.ExtractionOptions() { ExtractFullPath = true, Overwrite = true });
                    }
                }

                var extractFolderName = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Stardrop.app" : "Stardrop";
                var adjustedExtractFolderName = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "~Stardrop.app" : "~Stardrop";
                if (Directory.Exists(extractFolderName))
                {
                    if (Directory.Exists(adjustedExtractFolderName))
                    {
                        Directory.Delete(adjustedExtractFolderName, true);
                    }
                    Directory.Move(extractFolderName, adjustedExtractFolderName);
                }
                downloadedArchivePath = Path.Combine(Directory.GetCurrentDirectory(), adjustedExtractFolderName);
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to download latest the version of Stardrop: {ex}", Helper.Status.Alert);
            }
            client.Dispose();

            return downloadedArchivePath;
        }
    }
}


================================================
FILE: Stardrop/Utilities/External/NexusClient.cs
================================================
using Semver;
using Stardrop.Models.Data;
using Stardrop.Models.Data.Enums;
using Stardrop.Models.Nexus;
using Stardrop.Models.Nexus.Web;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace Stardrop.Utilities.External
{
    public static class Nexus
    {
        private static readonly Uri _baseUrl = new Uri("https://api.nexusmods.com/v1/");

        public static NexusClient? Client { get; private set; }

        public delegate void NexusClientChangedHandler(NexusClient? oldClient, NexusClient? newClient);
        public static event NexusClientChangedHandler? ClientChanged = null;

        /// <summary>
        /// If the user has entered their Nexus API key in a previous session, this will attempt to retreive
        /// it.
        /// </summary>
        /// <returns>The key, if it exists. Null otherwise.</returns>
        public static string? GetCachedKey()
        {
            if (Program.settings.NexusDetails?.Key is null || File.Exists(Pathing.GetNotionCachePath()) is false)
            {
                return null;
            }

            var pairedKeys = JsonSerializer.Deserialize<PairedKeys>(File.ReadAllText(Pathing.GetNotionCachePath()), new JsonSerializerOptions { AllowTrailingCommas = true });
            if (pairedKeys?.Vector is null || pairedKeys?.Lock is null)
            {
                return null;
            }

            try
            {
                return SimpleObscure.Decrypt(Program.settings.NexusDetails.Key, pairedKeys.Lock, pairedKeys.Vector);
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to parse API key when requested: {ex}");
            }

            return null;
        }

        /// <summary>
        /// Creates a new HttpClient configured with a Nexus API key, and validates it against the Nexus API.
        /// If successfully validated, sets <see cref="Client"/>, as well as returning a reference to it.
        /// If called when a <see cref="Client"/> is already set, the Client will be replaced.<br/>
        /// On success, fires <see cref="ClientChanged"/>, with the previous client (if any), and the new client.
        /// </summary>
        /// <param name="apiKey">The API key from Nexus mods that will be included in the 'apiKey' header when making calls.</param>
        /// <returns>The created client, if successful. Null otherwise.</returns>
        public static async Task<NexusClient?> CreateClient(string apiKey)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = _baseUrl;
            client.DefaultRequestHeaders.Add("apiKey", apiKey);
            client.DefaultRequestHeaders.Add("Application-Name", "Stardrop");
            client.DefaultRequestHeaders.Add("Application-Version", Program.ApplicationVersion);
            client.DefaultRequestHeaders.Add("User-Agent", $"Stardrop/{Program.ApplicationVersion} {Environment.OSVersion}");

            var nexusClient = new NexusClient(client);

            bool isKeyValid = await nexusClient.ValidateKey();
            if (isKeyValid is false)
            {
                return null;
            }

            ClientChanged?.Invoke(oldClient: Client, newClient: nexusClient);
            Client = nexusClient;
            return Client;
        }

        /// <summary>
        /// Nulls out the <see cref="Client"/>, and fires a <see cref="ClientChanged"/> event
        /// to give consumers a chance to clean up their event handlers.
        /// </summary>
        public static void ClearClient()
        {
            ClientChanged?.Invoke(oldClient: Client, newClient: null);
            Client = null;
        }
    }

    public class NexusClient
    {
        private const string _nxmPattern = @"nxm:\/\/(?<domain>stardewvalley)\/mods\/(?<mod>[0-9]+)\/files\/(?<file>[0-9]+)\?key=(?<key>.*)&expires=(?<expiry>[0-9]+)&user_id=(?<user>[0-9]+)";

        private readonly HttpClient _client;
        private NexusUser _settings = null!;

        internal int DailyRequestsLimit { get; private set; }
        internal int DailyRequestsRemaining { get; private set; }
        internal event EventHandler? DailyRequestLimitsChanged = null;
        internal event EventHandler<ModDownloadStartedEventArgs>? DownloadStarted = null;
        internal event EventHandler<ModDownloadProgressEventArgs>? DownloadProgressChanged = null;
        internal event EventHandler<ModDownloadCompletedEventArgs>? DownloadCompleted = null;
        internal event EventHandler<ModDownloadFailedEventArgs>? DownloadFailed = null;

        public NexusClient(HttpClient client)
        {
            _client = client;
        }

        /// <summary>
        /// Calls the /validate endpoint on Nexus Mods' API using the API key stored in this client upon creation.
        /// If the key is successfully validated, its information is cached in <see cref="Program.settings.NexusDetails"/>.<br/>
        /// Returns <see langword="false"/> if validation fails.
        /// </summary>
        public async Task<bool> ValidateKey()
        {
            try
            {
                var response = await _client.GetAsync("users/validate");
                if (!response.IsSuccessStatusCode || response.Content == null)
                {
                    Program.helper.Log($"Call to Nexus Mods failed. HTTP status code: {response.StatusCode}, {response.ReasonPhrase}");
                    if (response.Content == null)
                    {
                        Program.helper.Log($"No response from Nexus Mods!");
                    }
                    else
                    {
                        Program.helper.Log($"Response from Nexus Mods:\n{await response.Content.ReadAsStringAsync()}");
                    }
                    return false;
                }


                string content = await response.Content.ReadAsStringAsync();
                Validate validationModel = JsonSerializer.Deserialize<Validate>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!;

                if (validationModel is null || String.IsNullOrEmpty(validationModel.Message) is false)
                {
                    Program.helper.Log($"Unable to validate given API key for Nexus Mods");
                    Program.helper.Log($"Response from Nexus Mods:\n{content}");

                    return false;
                }

                if (Program.settings.NexusDetails is null)
                {
                    return false;
                }

                Program.settings.NexusDetails.Username = validationModel.Name;
                Program.settings.NexusDetails.IsPremium = validationModel.IsPremium;
                _settings = Program.settings.NexusDetails;

                UpdateRequestCounts(response.Headers);

                return true;
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to validate user's API key for Nexus Mods: {ex}", Helper.Status.Alert);
                return false;
            }
        }

        public async Task<ModDetails?> GetModDetailsViaNXM(NXM nxmData)
        {
            if (nxmData.Link is null)
            {
                return null;
            }

            var match = Regex.Match(Regex.Unescape(nxmData.Link), _nxmPattern);
            if (match.Success is false || match.Groups["domain"].ToString().ToLower() != "stardewvalley" || Int32.TryParse(match.Groups["mod"].ToString(), out int modId) is false)
            {
                return null;
            }

            try
            {
                var response = await _client.GetAsync($"games/stardewvalley/mods/{modId}.json");
                if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content is not null)
                {
                    string content = await response.Content.ReadAsStringAsync();
                    ModDetails modDetails = JsonSerializer.Deserialize<ModDetails>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

                    if (modDetails is null)
                    {
                        Program.helper.Log($"Unable to get mod details for the mod {modId} on Nexus Mods");
                        Program.helper.Log($"Response from Nexus Mods:\n{content}");

                        return null;
                    }

                    UpdateRequestCounts(response.Headers);

                    return modDetails;
                }
                else
                {
                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        Program.helper.Log($"Bad status given from Nexus Mods: {response.StatusCode}");
                        if (response.Content is not null)
                        {
                            Program.helper.Log($"Response from Nexus Mods:\n{await response.Content.ReadAsStringAsync()}");
                        }
                    }
                    else if (response.Content is null)
                    {
                        Program.helper.Log($"No response from Nexus Mods!");
                    }
                }
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Unable to get mod details for the mod {modId} on Nexus Mods: {ex}", Helper.Status.Alert);
            }

            return null;
        }

        public async Task<ModFile?> GetFileByVersion(int modId, string version, string? modFlag = null)
        {
            if (SemVersion.TryParse(version.Replace("v", String.Empty), SemVersionStyles.Any, out var targetVersion) is false)
            {
                Program.helper.Log($"Unable to parse given target version {version}");
                return null;
            }

            Program.helper.Log($"Requesting version {version} of mod {modId}{(String.IsNullOrEmpty(modFlag) is false ? $" with flag {modFlag}" : String.Empty)}");

            try
            {
                var response = await _client.GetAsync($"games/stardewvalley/mods/{modId}/files.json");
                if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content is not null)
                {
                    string content = await response.Content.ReadAsStringAsync();
                    ModFiles modFiles = JsonSerializer.Deserialize<ModFiles>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

                    if (modFiles is null || modFiles.Files is null || modFiles.Files.Count == 0)
                    {
                        Program.helper.Log($"Unable to get the mod file for Nexus Mods");
                        Program.helper.Log($"Response from Nexus Mods:\n{content}");
                    }
                    else
                    {
                        ModFile? selectedFile = null;
                        foreach (var file in modFiles.Files.Where(x => String.IsNullOrEmpty(x.Version) is false && SemVersion.TryParse(x.Version.Replace("v", String.Empty), SemVersionStyles.Any, out var modVersion) && modVersion == targetVersion))
                        {
                            if (String.IsNullOrEmpty(modFlag) is false && ((String.IsNullOrEmpty(file.Name) is false && file.Name.Contains(modFlag, StringComparison.OrdinalIgnoreCase)) || (String.IsNullOrEmpty(file.Description) is false && file.Description.Contains(modFlag, StringComparison.OrdinalIgnoreCase))))
                            {
                                selectedFile = file;
                            }
                            else if (String.IsNullOrEmpty(modFlag) is true && String.IsNullOrEmpty(file.Category) is false && file.Category.Equals("MAIN", StringComparison.OrdinalIgnoreCase))
                            {
                                selectedFile = file;
                            }
                        }

                        if (selectedFile is null)
                        {
                            Program.helper.Log($"Unable to get a matching file for the mod {modId} with version {version}{(String.IsNullOrEmpty(modFlag) is false ? $" and with the flag {modFlag}" : String.Empty)} via Nexus Mods: \n{String.Join("\n", modFiles.Files.Select(m => $"{m.Name} | {m.Version}"))}");
                        }

                        UpdateRequestCounts(response.Headers);

                        return selectedFile;
                    }
                }
                else
                {
                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        Program.helper.Log($"Bad status given from Nexus Mods: {response.StatusCode}");
                        if (response.Content is not null)
                        {
                            Program.helper.Log($"Response from Nexus Mods:\n{await response.Content.ReadAsStringAsync()}");
                        }
                    }
                    else if (response.Content is null)
                    {
                        Program.helper.Log($"No response from Nexus Mods!");
                    }
                }
            }
            catch (Exception ex)
            {
                Program.helper.Log($"Failed to get the mod file for Nexus Mods: {ex}", Helper.Status.Alert);
            }

            return null;
        }

        public async Task<string?> GetFileDownloadLink(NXM nxmData, string? serverName = null)
        {
            if (nxmData.Link is null)
            {
                return null;
            }

            var match = Regex.Match(Regex.Unescape(nxmData.Link), _nxmPattern);
            if (match.Success is false || match.Groups["domain"].ToString().ToLower() != "stardewvalley" || Int32.TryParse(match.Groups["mod"].ToString(), out int modId) is false || Int32.TryParse(match.Groups["file"].ToString(), out int fileId) is false)
            {
                return null;
            }

            return await GetFileDownloadLink(modId, fileId, match.Groups["key"].ToString(), match.Groups["expiry"].ToString(), serverName);
        }

        public async Task<string?> GetFileDownloadLink(int modId, int fileId, string? nxmKey = null, string? nxmExpiry = null, string? serverName = null)
        {
            if (String.IsNullOrEmpty(serverName) || _settings.IsPremium is false)
            {
                serverName = "Nexus CDN";
            }

            try
            {
                
Download .txt
gitextract_noi0fdfa/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── nightly-build.yml
│       ├── package-and-release.yml
│       ├── package.yml
│       ├── pr-target-action.yml
│       └── version-build.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
└── Stardrop/
    ├── App.axaml
    ├── App.axaml.cs
    ├── Assets/
    │   ├── Info.plist
    │   ├── Stardrop.icns
    │   └── Stardrop.sh
    ├── Converters/
    │   ├── EnumConverter.cs
    │   └── EnumEqualsConverter.cs
    ├── Models/
    │   ├── Config.cs
    │   ├── Data/
    │   │   ├── ClientData.cs
    │   │   ├── Enums/
    │   │   │   ├── Choice.cs
    │   │   │   ├── DisplayFilter.cs
    │   │   │   ├── EndorsementResponse.cs
    │   │   │   ├── InstallState.cs
    │   │   │   ├── ModGrouping.cs
    │   │   │   └── NexusServers.cs
    │   │   ├── LastSessionData.cs
    │   │   ├── ModDownloadEvents.cs
    │   │   ├── ModInstallData.cs
    │   │   ├── ModKeyInfo.cs
    │   │   ├── ModUpdateInfo.cs
    │   │   ├── PairedKeys.cs
    │   │   └── UpdateCache.cs
    │   ├── Mod.cs
    │   ├── Nexus/
    │   │   ├── NexusUser.cs
    │   │   └── Web/
    │   │       ├── DownloadLink.cs
    │   │       ├── Endorsement.cs
    │   │       ├── EndorsementResult.cs
    │   │       ├── ModDetails.cs
    │   │       ├── ModFile.cs
    │   │       ├── ModFiles.cs
    │   │       ├── NXM.cs
    │   │       ├── NexusConnectionResult.cs
    │   │       ├── Validate.cs
    │   │       ├── WebsocketResponse.cs
    │   │       └── WebsocketResponseData.cs
    │   ├── Profile.cs
    │   ├── SMAPI/
    │   │   ├── Converters/
    │   │   │   ├── BooleanConverter.cs
    │   │   │   ├── BooleanConverterAssumeTrue.cs
    │   │   │   └── ModKeyConverter.cs
    │   │   ├── GameDetails.cs
    │   │   ├── Manifest.cs
    │   │   ├── ManifestContentPackFor.cs
    │   │   ├── ManifestDependency.cs
    │   │   └── Web/
    │   │       ├── ModEntry.cs
    │   │       ├── ModEntryMetadata.cs
    │   │       ├── ModEntryVersion.cs
    │   │       ├── ModSearchData.cs
    │   │       └── ModSearchEntry.cs
    │   ├── Settings.cs
    │   └── Theme.cs
    ├── Program.cs
    ├── Properties/
    │   └── PublishProfiles/
    │       ├── FolderProfile - Linux.pubxml
    │       ├── FolderProfile - MacOS.pubxml
    │       └── FolderProfile - Windows.pubxml
    ├── Stardrop.csproj
    ├── Stardrop.sln
    ├── Themes/
    │   ├── Contributors/
    │   │   └── hotcereal/
    │   │       ├── CASH MONEY.xaml
    │   │       ├── Cerene Dark.xaml
    │   │       ├── Cerene Light.xaml
    │   │       ├── Dark Cherry Chocolate.xaml
    │   │       ├── Fairy.xaml
    │   │       ├── Forest.xaml
    │   │       ├── Light (Pink).xaml
    │   │       └── Light Cherry Chocolate.xaml
    │   ├── Dark.xaml
    │   ├── Light.xaml
    │   ├── Solarized-Lite.xaml
    │   └── Stardrop.xaml
    ├── Utilities/
    │   ├── Extension/
    │   │   └── TranslateExtension.cs
    │   ├── External/
    │   │   ├── GitHub.cs
    │   │   ├── NexusClient.cs
    │   │   ├── NexusDownloadResult.cs
    │   │   └── SMAPI.cs
    │   ├── Helper.cs
    │   ├── Internal/
    │   │   ├── EnumParser.cs
    │   │   └── ManifestParser.cs
    │   ├── JsonTools.cs
    │   ├── NXMProtocol.cs
    │   ├── NexusWebsocket.cs
    │   ├── Pathing.cs
    │   ├── SimpleObscure.cs
    │   └── Translation.cs
    ├── ViewLocator.cs
    ├── ViewModels/
    │   ├── DownloadPanelViewModel.cs
    │   ├── FlexibleOptionWindowViewModel.cs
    │   ├── MainWindowViewModel.cs
    │   ├── MessageWindowViewModel.cs
    │   ├── ModDownloadViewModel.cs
    │   ├── ProfileEditorViewModel.cs
    │   ├── SettingsWindowViewModel.cs
    │   ├── ViewModelBase.cs
    │   └── WarningWindowViewModel.cs
    ├── Views/
    │   ├── DownloadPanel.axaml
    │   ├── DownloadPanel.axaml.cs
    │   ├── FlexibleOptionWindow.axaml
    │   ├── FlexibleOptionWindow.axaml.cs
    │   ├── MainWindow.axaml
    │   ├── MainWindow.axaml.cs
    │   ├── MessageWindow.axaml
    │   ├── MessageWindow.axaml.cs
    │   ├── NexusInfo.axaml
    │   ├── NexusInfo.axaml.cs
    │   ├── NexusLogin.axaml
    │   ├── NexusLogin.axaml.cs
    │   ├── ProfileEditor.axaml
    │   ├── ProfileEditor.axaml.cs
    │   ├── ProfileNaming.axaml
    │   ├── ProfileNaming.axaml.cs
    │   ├── SettingsWindow.axaml
    │   ├── SettingsWindow.axaml.cs
    │   ├── WarningWindow.axaml
    │   └── WarningWindow.axaml.cs
    └── i18n/
        ├── de.json
        ├── default.json
        ├── es.json
        ├── fr.json
        ├── hu.json
        ├── it.json
        ├── ja.json
        ├── ko.json
        ├── pl.json
        ├── pt.json
        ├── ru.json
        ├── th.json
        ├── tr.json
        ├── uk.json
        └── zh.json
Download .txt
SYMBOL INDEX (432 symbols across 81 files)

FILE: Stardrop/App.axaml.cs
  class App (line 16) | public class App : Application
    method Initialize (line 18) | public override void Initialize()
    method OnUrlsOpen (line 50) | private async void OnUrlsOpen(object? sender, UrlOpenedEventArgs e, Ma...
    method OnFrameworkInitializationCompleted (line 58) | public override void OnFrameworkInitializationCompleted()

FILE: Stardrop/Converters/EnumConverter.cs
  class EnumConverter (line 7) | public class EnumConverter : IValueConverter
    method Convert (line 9) | public object Convert(object value, Type targetType, object parameter,...
    method ConvertBack (line 14) | public object ConvertBack(object value, Type targetType, object parame...

FILE: Stardrop/Converters/EnumEqualsConverter.cs
  class EnumEqualsConverter (line 7) | public class EnumEqualsConverter : IValueConverter
    method Convert (line 9) | public object? Convert(object? value, Type targetType, object? paramet...
    method ConvertBack (line 23) | public object? ConvertBack(object? value, Type targetType, object? par...

FILE: Stardrop/Models/Config.cs
  class Config (line 5) | public class Config

FILE: Stardrop/Models/Data/ClientData.cs
  class ClientData (line 5) | public class ClientData

FILE: Stardrop/Models/Data/Enums/Choice.cs
  type Choice (line 3) | public enum Choice

FILE: Stardrop/Models/Data/Enums/DisplayFilter.cs
  type DisplayFilter (line 3) | public enum DisplayFilter

FILE: Stardrop/Models/Data/Enums/EndorsementResponse.cs
  type InstallState (line 3) | public enum InstallState

FILE: Stardrop/Models/Data/Enums/InstallState.cs
  type EndorsementResponse (line 3) | public enum EndorsementResponse

FILE: Stardrop/Models/Data/Enums/ModGrouping.cs
  type ModGrouping (line 5) | public enum ModGrouping

FILE: Stardrop/Models/Data/Enums/NexusServers.cs
  type NexusServers (line 5) | public enum NexusServers

FILE: Stardrop/Models/Data/LastSessionData.cs
  class LastSessionData (line 6) | public class LastSessionData

FILE: Stardrop/Models/Data/ModDownloadEvents.cs
  type ModDownloadStartedEventArgs (line 6) | internal record ModDownloadStartedEventArgs(Uri Uri, string Name, long? ...
  type ModDownloadProgressEventArgs (line 7) | internal record ModDownloadProgressEventArgs(Uri Uri, long TotalBytes);
  type ModDownloadCompletedEventArgs (line 8) | internal record ModDownloadCompletedEventArgs(Uri Uri);
  type ModDownloadFailedEventArgs (line 9) | internal record ModDownloadFailedEventArgs(Uri Uri);

FILE: Stardrop/Models/Data/ModInstallData.cs
  class ModInstallData (line 5) | public class ModInstallData

FILE: Stardrop/Models/Data/ModKeyInfo.cs
  class ModKeyInfo (line 3) | public class ModKeyInfo

FILE: Stardrop/Models/Data/ModUpdateInfo.cs
  class ModUpdateInfo (line 5) | public class ModUpdateInfo
    method ModUpdateInfo (line 13) | public ModUpdateInfo()
    method ModUpdateInfo (line 18) | public ModUpdateInfo(string uniqueId, string recommendedVersion, WikiC...

FILE: Stardrop/Models/Data/PairedKeys.cs
  class PairedKeys (line 3) | public class PairedKeys

FILE: Stardrop/Models/Data/UpdateCache.cs
  class UpdateCache (line 6) | public class UpdateCache
    method UpdateCache (line 11) | public UpdateCache(DateTime lastRuntime)

FILE: Stardrop/Models/Mod.cs
  class Mod (line 19) | public class Mod : INotifyPropertyChanged
    method Mod (line 120) | public Mod(Manifest manifest, FileInfo modFileInfo, string uniqueId, s...
    method ComputeModPath (line 136) | private string ComputeModPath(FileInfo modFileInfo)
    method GetRootPath (line 172) | private string GetRootPath(string path)
    method IsModOutdated (line 183) | public bool IsModOutdated(string version)
    method HasValidVersion (line 193) | public bool HasValidVersion()
    method HasUpdateKeys (line 203) | public bool HasUpdateKeys()
    method GetNexusId (line 213) | public int? GetNexusId()
    method GetNexusFlag (line 236) | public string? GetNexusFlag()
    method TryLoadThumbnail (line 259) | private Bitmap? TryLoadThumbnail(string? filePath)
    method NotifyPropertyChanged (line 278) | internal void NotifyPropertyChanged([CallerMemberName] String property...

FILE: Stardrop/Models/Nexus/NexusUser.cs
  class NexusUser (line 3) | public class NexusUser
    method NexusUser (line 10) | public NexusUser()
    method NexusUser (line 15) | public NexusUser(string username, byte[] key)

FILE: Stardrop/Models/Nexus/Web/DownloadLink.cs
  class DownloadLink (line 5) | public class DownloadLink

FILE: Stardrop/Models/Nexus/Web/Endorsement.cs
  class EndorsementResult (line 5) | public class EndorsementResult

FILE: Stardrop/Models/Nexus/Web/EndorsementResult.cs
  class Endorsement (line 5) | public class Endorsement
    method IsEndorsed (line 16) | public bool IsEndorsed()

FILE: Stardrop/Models/Nexus/Web/ModDetails.cs
  class ModDetails (line 5) | public class ModDetails

FILE: Stardrop/Models/Nexus/Web/ModFile.cs
  class ModFile (line 5) | public class ModFile

FILE: Stardrop/Models/Nexus/Web/ModFiles.cs
  class ModFiles (line 6) | public class ModFiles

FILE: Stardrop/Models/Nexus/Web/NXM.cs
  class NXM (line 5) | public class NXM

FILE: Stardrop/Models/Nexus/Web/NexusConnectionResult.cs
  class NexusConnectionResult (line 9) | public class NexusConnectionResult

FILE: Stardrop/Models/Nexus/Web/Validate.cs
  class Validate (line 5) | public class Validate

FILE: Stardrop/Models/Nexus/Web/WebsocketResponse.cs
  class WebsocketResponse (line 10) | public class WebsocketResponse

FILE: Stardrop/Models/Nexus/Web/WebsocketResponseData.cs
  class WebsocketResponseData (line 10) | public class WebsocketResponseData

FILE: Stardrop/Models/Profile.cs
  class Profile (line 6) | public class Profile
    method Profile (line 13) | public Profile()
    method Profile (line 21) | public Profile(string name, bool isProtected = false, List<string>? en...
    method ShallowCopy (line 29) | public Profile ShallowCopy()

FILE: Stardrop/Models/SMAPI/Converters/BooleanConverter.cs
  class BooleanConverter (line 7) | internal class BooleanConverter : JsonConverter<bool>
    method Read (line 9) | public override bool Read(ref Utf8JsonReader reader, Type typeToConver...
    method Write (line 25) | public override void Write(Utf8JsonWriter writer, bool value, JsonSeri...

FILE: Stardrop/Models/SMAPI/Converters/BooleanConverterAssumeTrue.cs
  class BooleanConverterAssumeTrue (line 7) | internal class BooleanConverterAssumeTrue : JsonConverter<bool>
    method Read (line 9) | public override bool Read(ref Utf8JsonReader reader, Type typeToConver...
    method Write (line 25) | public override void Write(Utf8JsonWriter writer, bool value, JsonSeri...

FILE: Stardrop/Models/SMAPI/Converters/ModKeyConverter.cs
  class ModKeyConverter (line 8) | internal class ModKeyConverter : JsonConverter<string[]>
    method Read (line 10) | public override string[] Read(ref Utf8JsonReader reader, Type typeToCo...
    method Write (line 39) | public override void Write(Utf8JsonWriter writer, string[] value, Json...

FILE: Stardrop/Models/SMAPI/GameDetails.cs
  class GameDetails (line 6) | public class GameDetails
    type OS (line 8) | public enum OS
    method GameDetails (line 25) | public GameDetails()
    method GameDetails (line 30) | public GameDetails(string gameVersion, string smapiVersion, string sys...
    method HasSMAPIUpdated (line 53) | public bool HasSMAPIUpdated(string version)
    method HasSMAPIUpdated (line 63) | public bool HasSMAPIUpdated(SemVersion version)
    method HasBadGameVersion (line 73) | public bool HasBadGameVersion()

FILE: Stardrop/Models/SMAPI/Manifest.cs
  class Manifest (line 6) | public class Manifest

FILE: Stardrop/Models/SMAPI/ManifestContentPackFor.cs
  class ManifestContentPackFor (line 3) | public class ManifestContentPackFor

FILE: Stardrop/Models/SMAPI/ManifestDependency.cs
  class ManifestDependency (line 7) | public class ManifestDependency : INotifyPropertyChanged
    method ManifestDependency (line 28) | public ManifestDependency(string uniqueId, string minimumVersion, bool...
    method NotifyPropertyChanged (line 35) | private void NotifyPropertyChanged(string propertyName)

FILE: Stardrop/Models/SMAPI/Web/ModEntry.cs
  class ModEntry (line 3) | public class ModEntry

FILE: Stardrop/Models/SMAPI/Web/ModEntryMetadata.cs
  class ModEntryMetadata (line 5) | public class ModEntryMetadata
    type WikiCompatibilityStatus (line 9) | public enum WikiCompatibilityStatus

FILE: Stardrop/Models/SMAPI/Web/ModEntryVersion.cs
  class ModEntryVersion (line 3) | public class ModEntryVersion
    method ModEntryVersion (line 21) | public ModEntryVersion() { }
    method ModEntryVersion (line 26) | public ModEntryVersion(string version, string url)

FILE: Stardrop/Models/SMAPI/Web/ModSearchData.cs
  class ModSearchData (line 5) | class ModSearchData
    method ModSearchData (line 32) | public ModSearchData()
    method ModSearchData (line 43) | public ModSearchData(List<ModSearchEntry> mods, string apiVersion, str...

FILE: Stardrop/Models/SMAPI/Web/ModSearchEntry.cs
  class ModSearchEntry (line 5) | public class ModSearchEntry
    method ModSearchEntry (line 26) | public ModSearchEntry()
    method ModSearchEntry (line 36) | public ModSearchEntry(string id, SemVersion installedVersion, string[]...

FILE: Stardrop/Models/Settings.cs
  class Settings (line 7) | public class Settings
    method ShallowCopy (line 32) | public Settings ShallowCopy()

FILE: Stardrop/Models/Theme.cs
  class Theme (line 10) | public class Theme

FILE: Stardrop/Program.cs
  class Program (line 26) | class Program
    class Options (line 42) | public class Options
    method Main (line 53) | [STAThread]
    method HandleSecondaryInstance (line 160) | private static void HandleSecondaryInstance(string[] args)
    method BuildAvaloniaApp (line 236) | public static AppBuilder BuildAvaloniaApp()

FILE: Stardrop/Utilities/Extension/TranslateExtension.cs
  class TranslateExtension (line 9) | public class TranslateExtension : MarkupExtension
    method TranslateExtension (line 11) | public TranslateExtension(string key)
    method ProvideValue (line 20) | public override object ProvideValue(IServiceProvider serviceProvider)

FILE: Stardrop/Utilities/External/GitHub.cs
  class GitHub (line 13) | static class GitHub
    method GetLatestSMAPIRelease (line 15) | public async static Task<KeyValuePair<string, string>?> GetLatestSMAPI...
    method DownloadLatestSMAPIRelease (line 46) | public async static Task<string> DownloadLatestSMAPIRelease(string uri)
    method GetLatestStardropRelease (line 74) | public async static Task<KeyValuePair<string, string>?> GetLatestStard...
    method DownloadLatestStardropRelease (line 117) | public async static Task<string> DownloadLatestStardropRelease(string ...

FILE: Stardrop/Utilities/External/NexusClient.cs
  class Nexus (line 20) | public static class Nexus
    method GetCachedKey (line 34) | public static string? GetCachedKey()
    method CreateClient (line 67) | public static async Task<NexusClient?> CreateClient(string apiKey)
    method ClearClient (line 93) | public static void ClearClient()
  class NexusClient (line 100) | public class NexusClient
    method NexusClient (line 115) | public NexusClient(HttpClient client)
    method ValidateKey (line 125) | public async Task<bool> ValidateKey()
    method GetModDetailsViaNXM (line 176) | public async Task<ModDetails?> GetModDetailsViaNXM(NXM nxmData)
    method GetFileByVersion (line 233) | public async Task<ModFile?> GetFileByVersion(int modId, string version...
    method GetFileDownloadLink (line 305) | public async Task<string?> GetFileDownloadLink(NXM nxmData, string? se...
    method GetFileDownloadLink (line 321) | public async Task<string?> GetFileDownloadLink(int modId, int fileId, ...
    method DownloadFileAndGetPath (line 383) | public async Task<NexusDownloadResult> DownloadFileAndGetPath(string u...
    method GetEndorsements (line 435) | public async Task<List<Endorsement>> GetEndorsements()
    method SetModEndorsement (line 483) | public async Task<EndorsementResponse> SetModEndorsement(int modId, bo...
    method DownloadThumbnail (line 544) | public async Task<string?> DownloadThumbnail(int modId)
    method UpdateRequestCounts (line 605) | private void UpdateRequestCounts(HttpResponseHeaders headers)

FILE: Stardrop/Utilities/External/NexusDownloadResult.cs
  type DownloadResultKind (line 3) | public enum DownloadResultKind
  type NexusDownloadResult (line 10) | public record struct NexusDownloadResult(DownloadResultKind ResultKind, ...

FILE: Stardrop/Utilities/External/SMAPI.cs
  class SMAPI (line 19) | static class SMAPI
    method GetPrepareProcess (line 24) | public static ProcessStartInfo GetPrepareProcess(bool hideConsole)
    method GetProcessName (line 83) | public static string GetProcessName()
    method GetModUpdateData (line 93) | public async static Task<List<ModEntry>> GetModUpdateData(GameDetails ...
    method GetVersion (line 162) | internal static SemVersion? GetVersion()

FILE: Stardrop/Utilities/Helper.cs
  class Helper (line 8) | internal class Helper
    type Status (line 20) | public enum Status { Debug, Alert, Warning, Info };
    method Helper (line 22) | public Helper(string fileName = "log", string fileExtension = ".txt", ...
    method GetLogPath (line 44) | public string GetLogPath()
    method DisableTracing (line 49) | public void DisableTracing()
    method IsActive (line 59) | public bool IsActive()
    method Log (line 66) | public void Log(string message, Status status = Status.Debug, [CallerM...
    method Log (line 75) | public void Log(object messageObj, Status status = Status.Debug, [Call...
    method HasAlert (line 88) | public bool HasAlert()
    method HasWarning (line 93) | public bool HasWarning()
    method HasInfo (line 98) | public bool HasInfo()
    method HasDebug (line 103) | public bool HasDebug()
    method TrackStatus (line 110) | private void TrackStatus(Status status)

FILE: Stardrop/Utilities/Internal/EnumParser.cs
  class EnumParser (line 7) | internal static class EnumParser
    method GetDescription (line 10) | public static string? GetDescription(this Enum? value)

FILE: Stardrop/Utilities/Internal/ManifestParser.cs
  class ManifestParser (line 10) | internal static class ManifestParser
    method GetDataAsync (line 12) | public static async Task<Manifest?> GetDataAsync(IArchiveEntry manifes...
    method GetData (line 23) | public static Manifest? GetData(string manifestText)

FILE: Stardrop/Utilities/JsonTools.cs
  class JsonTools (line 10) | internal class JsonTools
    method ParseDocumentToString (line 13) | public static string ParseDocumentToString(JsonDocument jdoc)
    method Merge (line 26) | public static string Merge(string originalJson, string newContent, boo...
    method MergeObjects (line 60) | private static void MergeObjects(Utf8JsonWriter jsonWriter, JsonElemen...
    method MergeArrays (line 119) | private static void MergeArrays(Utf8JsonWriter jsonWriter, JsonElement...

FILE: Stardrop/Utilities/NXMProtocol.cs
  class NXMProtocol (line 7) | internal static class NXMProtocol
    method Register (line 9) | public static bool Register(string applicationPath)
    method Validate (line 33) | public static bool Validate(string applicationPath)

FILE: Stardrop/Utilities/NexusWebsocket.cs
  class NexusWebsocket (line 14) | internal class NexusWebsocket
    method NexusWebsocket (line 26) | public NexusWebsocket()
    method ConnectAsync (line 31) | public async Task<NexusConnectionResult> ConnectAsync(CancellationToke...

FILE: Stardrop/Utilities/Pathing.cs
  class Pathing (line 7) | public static class Pathing
    method SetHomePath (line 13) | internal static void SetHomePath(string homePath)
    method SetSmapiPath (line 18) | internal static void SetSmapiPath(string smapiPath, bool useDefaultMod...
    method SetModPath (line 31) | internal static void SetModPath(string modPath)
    method GetLogFolderPath (line 39) | internal static string GetLogFolderPath()
    method GetSettingsPath (line 44) | internal static string GetSettingsPath()
    method GetProfilesFolderPath (line 49) | public static string GetProfilesFolderPath()
    method GetSelectedModsFolderPath (line 54) | public static string GetSelectedModsFolderPath()
    method GetSmapiPath (line 59) | public static string GetSmapiPath()
    method GetSmapiLogFolderPath (line 64) | internal static string GetSmapiLogFolderPath()
    method GetCacheFolderPath (line 74) | public static string GetCacheFolderPath()
    method GetVersionCachePath (line 79) | public static string GetVersionCachePath()
    method GetKeyCachePath (line 84) | internal static string GetKeyCachePath()
    method GetDataCachePath (line 89) | internal static string GetDataCachePath()
    method GetNotionCachePath (line 94) | public static string GetNotionCachePath()
    method GetLinksCachePath (line 99) | public static string GetLinksCachePath()
    method GetNexusPath (line 104) | public static string GetNexusPath()
    method GetThumbnailsPath (line 109) | public static string GetThumbnailsPath()
    method GetSmapiUpgradeFolderPath (line 114) | public static string GetSmapiUpgradeFolderPath()

FILE: Stardrop/Utilities/SimpleObscure.cs
  class SimpleObscure (line 6) | internal class SimpleObscure
    method SimpleObscure (line 11) | public SimpleObscure()
    method Encrypt (line 20) | internal static byte[] Encrypt(string plainText, byte[] Key, byte[] IV)
    method Decrypt (line 49) | internal static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)

FILE: Stardrop/Utilities/Translation.cs
  class Translation (line 10) | internal class Translation : INotifyPropertyChanged
    type Language (line 12) | public enum Language
    type LanguageAbbreviation (line 30) | public enum LanguageAbbreviation
    method Translation (line 56) | public Translation()
    method GetLanguageFromAbbreviation (line 68) | public string GetLanguageFromAbbreviation(string abbreviation)
    method GetLanguage (line 81) | public Language GetLanguage(string language)
    method SetLanguage (line 91) | public void SetLanguage(string language)
    method SetLanguage (line 99) | public void SetLanguage(Language language)
    method LoadTranslations (line 106) | public void LoadTranslations()
    method LoadTranslations (line 127) | public void LoadTranslations(Language language)
    method GetAvailableTranslations (line 135) | public List<Language> GetAvailableTranslations()
    method Get (line 146) | public string Get(string key)
    method Invalidate (line 170) | public void Invalidate()

FILE: Stardrop/ViewLocator.cs
  class ViewLocator (line 8) | public class ViewLocator : IDataTemplate
    method Build (line 10) | public IControl Build(object data)
    method Match (line 25) | public bool Match(object data)

FILE: Stardrop/ViewModels/DownloadPanelViewModel.cs
  class DownloadPanelViewModel (line 15) | public class DownloadPanelViewModel : ViewModelBase
    method DownloadPanelViewModel (line 22) | public DownloadPanelViewModel(NexusClient? nexusClient)
    method NexusClientChanged (line 39) | private void NexusClientChanged(NexusClient? oldClient, NexusClient? n...
    method RegisterEventHandlers (line 58) | private void RegisterEventHandlers(NexusClient nexusClient)
    method ClearEventHandlers (line 66) | private void ClearEventHandlers(NexusClient nexusClient)
    method DownloadStarted (line 74) | private void DownloadStarted(object? sender, ModDownloadStartedEventAr...
    method DownloadProgressChanged (line 100) | private void DownloadProgressChanged(object? sender, ModDownloadProgre...
    method DownloadCompleted (line 110) | private void DownloadCompleted(object? sender, ModDownloadCompletedEve...
    method DownloadFailed (line 119) | private void DownloadFailed(object? sender, ModDownloadFailedEventArgs e)
    method DownloadRemovalRequested (line 128) | private void DownloadRemovalRequested(object? sender, EventArgs _)
    method DownloadPanelViewModel (line 140) | public DownloadPanelViewModel()

FILE: Stardrop/ViewModels/FlexibleOptionWindowViewModel.cs
  class FlexibleOptionWindowViewModel (line 5) | public class FlexibleOptionWindowViewModel : ViewModelBase

FILE: Stardrop/ViewModels/MainWindowViewModel.cs
  class MainWindowViewModel (line 25) | public class MainWindowViewModel : ViewModelBase
    method MainWindowViewModel (line 88) | public MainWindowViewModel(string modsFilePath, string version)
    method OpenBrowser (line 117) | public void OpenBrowser(string url)
    method ChangeColumnVisibility (line 141) | public void ChangeColumnVisibility(MenuItem column)
    method SetColumnVisibility (line 164) | public void SetColumnVisibility(MenuItem column, DataGrid modGrid, boo...
    method ParentFolderContainsPeriod (line 200) | public bool ParentFolderContainsPeriod(string oldestAncestorPath, Dire...
    method GetManifestFiles (line 225) | public List<FileInfo> GetManifestFiles(DirectoryInfo modDirectory)
    method DiscoverMods (line 251) | public void DiscoverMods(string modsFilePath)
    method HideRequiredMods (line 392) | public void HideRequiredMods()
    method EvaluateRequirements (line 408) | public void EvaluateRequirements()
    method GetConfigFiles (line 446) | public List<FileInfo> GetConfigFiles(DirectoryInfo modDirectory)
    method DiscoverConfigs (line 468) | public void DiscoverConfigs(string modsFilePath, bool useArchive = false)
    method GetPendingConfigUpdates (line 504) | internal List<Config> GetPendingConfigUpdates(Profile profile, bool ex...
    method UpdateEndorsements (line 569) | internal async void UpdateEndorsements()
    method UpdateThumbnails (line 583) | internal async void UpdateThumbnails()
    method ReadModConfigs (line 608) | internal void ReadModConfigs(Profile profile)
    method ReadModConfigs (line 613) | internal void ReadModConfigs(Profile profile, List<Config> pendingConf...
    method WriteModConfigs (line 628) | internal bool WriteModConfigs(Profile profile)
    method WriteModConfigs (line 633) | internal bool WriteModConfigs(Profile profile, List<Config> pendingCon...
    method EnableModsByProfile (line 663) | public void EnableModsByProfile(Profile profile)
    method ForceModState (line 679) | public void ForceModState(Profile profile, List<Mod> mods, bool modEna...
    method UpdateDataGridGrouping (line 694) | internal void UpdateDataGridGrouping()
    method UpdateFilter (line 731) | internal void UpdateFilter()
    method ModFilter (line 742) | private bool ModFilter(object item)
    method DataViewSortDescription_CollectionChanged (line 843) | private void DataViewSortDescription_CollectionChanged(object? sender,...
    method HandleModGroupingSorting (line 848) | private void HandleModGroupingSorting()

FILE: Stardrop/ViewModels/MessageWindowViewModel.cs
  class MessageWindowViewModel (line 5) | public class MessageWindowViewModel : ViewModelBase

FILE: Stardrop/ViewModels/ModDownloadViewModel.cs
  type ModDownloadStatus (line 10) | public enum ModDownloadStatus
  class ModDownloadViewModel (line 19) | public class ModDownloadViewModel : ViewModelBase
    method ModDownloadViewModel (line 63) | public ModDownloadViewModel(Uri modUri, string name, long? sizeInBytes...
    method Cancel (line 145) | private void Cancel()
    method Remove (line 151) | private void Remove()

FILE: Stardrop/ViewModels/ProfileEditorViewModel.cs
  class ProfileEditorViewModel (line 12) | public class ProfileEditorViewModel : ViewModelBase
    method ProfileEditorViewModel (line 21) | public ProfileEditorViewModel(string profilesFilePath)
    method CreateProfile (line 78) | internal void CreateProfile(Profile profile, bool force = false)
    method DeleteProfile (line 90) | internal void DeleteProfile(Profile profile)
    method UpdateProfile (line 102) | internal void UpdateProfile(Profile profile, List<string> enabledModIds)

FILE: Stardrop/ViewModels/SettingsWindowViewModel.cs
  class SettingsWindowViewModel (line 9) | public class SettingsWindowViewModel : ViewModelBase
    method SettingsWindowViewModel (line 47) | public SettingsWindowViewModel()

FILE: Stardrop/ViewModels/ViewModelBase.cs
  class ViewModelBase (line 5) | public class ViewModelBase : ReactiveObject

FILE: Stardrop/ViewModels/WarningWindowViewModel.cs
  class WarningWindowViewModel (line 5) | public class WarningWindowViewModel : ViewModelBase
    method WarningWindowViewModel (line 18) | public WarningWindowViewModel()

FILE: Stardrop/Views/DownloadPanel.axaml.cs
  class DownloadPanel (line 9) | public partial class DownloadPanel : UserControl
    method DownloadPanel (line 13) | public DownloadPanel()

FILE: Stardrop/Views/FlexibleOptionWindow.axaml.cs
  class FlexibleOptionWindow (line 10) | public partial class FlexibleOptionWindow : Window
    method FlexibleOptionWindow (line 14) | public FlexibleOptionWindow()
    method FlexibleOptionWindow (line 27) | public FlexibleOptionWindow(string messageText, string? firstButtonTex...
    method Button_Click (line 51) | private void Button_Click(object? sender, Avalonia.Interactivity.Route...
    method InitializeComponent (line 73) | private void InitializeComponent()

FILE: Stardrop/Views/MainWindow.axaml.cs
  class MainWindow (line 37) | public partial class MainWindow : Window
    method MainWindow (line 55) | public MainWindow()
    method ModGrid_LoadingRowGroup (line 209) | private void ModGrid_LoadingRowGroup(object? sender, DataGridRowGroupH...
    method MainWindow_KeyDown (line 214) | private void MainWindow_KeyDown(object? sender, KeyEventArgs e)
    method MainWindow_KeyUp (line 232) | private void MainWindow_KeyUp(object? sender, KeyEventArgs e)
    method MainWindow_PropertyChanged (line 244) | private async void MainWindow_PropertyChanged(object? sender, Avalonia...
    method MainWindow_Closing (line 259) | private void MainWindow_Closing(object? sender, System.ComponentModel....
    method MainWindow_Opened (line 286) | private async void MainWindow_Opened(object? sender, EventArgs e)
    method CreateWarningWindow (line 356) | private async Task CreateWarningWindow(string warningText, string butt...
    method Drop (line 362) | private async void Drop(object sender, DragEventArgs e)
    method _smapiProcessTimer_Tick (line 388) | private void _smapiProcessTimer_Tick(object? sender, EventArgs e)
    method _nxmSentinelTimer_Tick (line 408) | private async void _nxmSentinelTimer_Tick(object? sender, EventArgs e)
    method _lockSentinelTimer_Tick (line 465) | private async void _lockSentinelTimer_Tick(object? sender, EventArgs e)
    method ModGridMenuRow_ChangeState (line 477) | private void ModGridMenuRow_ChangeState(object? sender, Avalonia.Inter...
    method ModGridMenuRow_ChangeWholeModGroupState (line 510) | private void ModGridMenuRow_ChangeWholeModGroupState(object? sender, A...
    method EnableDisableSelectedMods (line 550) | private void EnableDisableSelectedMods(DataGrid? modGrid, Mod? selecte...
    method ModGridMenuRow_OpenFolderPath (line 581) | private void ModGridMenuRow_OpenFolderPath(object? sender, Avalonia.In...
    method ModGridMenuRow_OpenModPage (line 592) | private void ModGridMenuRow_OpenModPage(object? sender, Avalonia.Inter...
    method ModGridMenuRow_ShowWholeModGroup (line 603) | private void ModGridMenuRow_ShowWholeModGroup(object? sender, Avalonia...
    method ModGridMenuRow_ShowAuthorsMods (line 634) | private void ModGridMenuRow_ShowAuthorsMods(object? sender, Avalonia.I...
    method ModGridMenuRow_ClearFilter (line 649) | private void ModGridMenuRow_ClearFilter(object? sender, Avalonia.Inter...
    method ModGridMenuRow_Delete (line 661) | private async void ModGridMenuRow_Delete(object? sender, Avalonia.Inte...
    method SearchBox_KeyUp (line 718) | private void SearchBox_KeyUp(object? sender, KeyEventArgs e)
    method SearchBoxTimer_Tick (line 729) | private void SearchBoxTimer_Tick(object? sender, EventArgs e)
    method FilterListBox_SelectionChanged (line 746) | private void FilterListBox_SelectionChanged(object? sender, SelectionC...
    method DisabledModComboBox_SelectionChanged (line 755) | private void DisabledModComboBox_SelectionChanged(object? sender, Sele...
    method ShowUpdatableModsButton_Click (line 778) | private void ShowUpdatableModsButton_Click(object? sender, Avalonia.In...
    method ProfileComboBox_SelectionChanged (line 784) | private async void ProfileComboBox_SelectionChanged(object? sender, Se...
    method EndorsementButton_Click (line 818) | private async void EndorsementButton_Click(object? sender, Avalonia.In...
    method InstallButton_Click (line 865) | private async void InstallButton_Click(object? sender, Avalonia.Intera...
    method EnabledBox_Clicked (line 903) | private void EnabledBox_Clicked(object? sender, Avalonia.Interactivity...
    method EditProfilesButton_Click (line 954) | private async void EditProfilesButton_Click(object? sender, Avalonia.I...
    method SaveConfigButton_Click (line 974) | private void SaveConfigButton_Click(object? sender, Avalonia.Interacti...
    method ModGroupStateButton (line 994) | private void ModGroupStateButton(object? sender, Avalonia.Interactivit...
    method NexusModsButton_Click (line 1026) | private async void NexusModsButton_Click(object? sender, Avalonia.Inte...
    method SaveProfileChanges_Click (line 1032) | private async void SaveProfileChanges_Click(object? sender, Avalonia.I...
    method SaveProfileChanges_Click (line 1037) | private async void SaveProfileChanges_Click(object? sender, EventArgs e)
    method Smapi_Click (line 1042) | private async void Smapi_Click(object? sender, Avalonia.Interactivity....
    method Smapi_Click (line 1047) | private async void Smapi_Click(object? sender, EventArgs e)
    method AddMod_Click (line 1052) | private async void AddMod_Click(object? sender, Avalonia.Interactivity...
    method AddMod_Click (line 1057) | private async void AddMod_Click(object? sender, EventArgs e)
    method Settings_Click (line 1062) | private async void Settings_Click(object? sender, Avalonia.Interactivi...
    method Settings_Click (line 1067) | private async void Settings_Click(object? sender, EventArgs e)
    method LogFile_Click (line 1072) | private void LogFile_Click(object? sender, Avalonia.Interactivity.Rout...
    method LogFile_Click (line 1077) | private void LogFile_Click(object? sender, EventArgs e)
    method SmapiLogFile_Click (line 1082) | private void SmapiLogFile_Click(object? sender, Avalonia.Interactivity...
    method SmapiLogFile_Click (line 1087) | private void SmapiLogFile_Click(object? sender, EventArgs e)
    method ModUpdateCheck_Click (line 1092) | private async void ModUpdateCheck_Click(object? sender, Avalonia.Inter...
    method ModUpdateCheck_Click (line 1097) | private async void ModUpdateCheck_Click(object? sender, EventArgs e)
    method StardropUpdate_Click (line 1102) | private async void StardropUpdate_Click(object? sender, Avalonia.Inter...
    method StardropUpdate_Click (line 1107) | private async void StardropUpdate_Click(object? sender, EventArgs e)
    method SMAPIUpdate_Click (line 1112) | private async void SMAPIUpdate_Click(object? sender, Avalonia.Interact...
    method SMAPIUpdate_Click (line 1117) | private async void SMAPIUpdate_Click(object? sender, EventArgs e)
    method ModListRefresh_Click (line 1122) | private async void ModListRefresh_Click(object? sender, Avalonia.Inter...
    method ModListRefresh_Click (line 1127) | private async void ModListRefresh_Click(object? sender, EventArgs e)
    method NexusModBulkInstall_Click (line 1132) | private async void NexusModBulkInstall_Click(object? sender, Avalonia....
    method NexusModBulkInstall_Click (line 1137) | private async void NexusModBulkInstall_Click(object? sender, EventArgs e)
    method NexusModBulkInstallEnabledOnly_Click (line 1142) | private async void NexusModBulkInstallEnabledOnly_Click(object? sender...
    method NexusModBulkInstallEnabledOnly_Click (line 1147) | private async void NexusModBulkInstallEnabledOnly_Click(object? sender...
    method NexusConnection_Click (line 1152) | private async void NexusConnection_Click(object? sender, Avalonia.Inte...
    method NexusConnection_Click (line 1157) | private async void NexusConnection_Click(object? sender, EventArgs e)
    method EnableAllMods_Click (line 1162) | private async void EnableAllMods_Click(object? sender, Avalonia.Intera...
    method EnableAllMods_Click (line 1167) | private async void EnableAllMods_Click(object? sender, EventArgs e)
    method DisableAllMods_Click (line 1172) | private async void DisableAllMods_Click(object? sender, Avalonia.Inter...
    method DisableAllMods_Click (line 1177) | private async void DisableAllMods_Click(object? sender, EventArgs e)
    method Exit_Click (line 1182) | private void Exit_Click(object? sender, Avalonia.Interactivity.RoutedE...
    method Exit_Click (line 1187) | private void Exit_Click(object? sender, EventArgs e)
    method MainBar_DoubleTapped (line 1192) | private void MainBar_DoubleTapped(object? sender, Avalonia.Interactivi...
    method MainBar_PointerPressed (line 1201) | private void MainBar_PointerPressed(object? sender, Avalonia.Input.Poi...
    method SaveChanges (line 1211) | private async Task SaveChanges()
    method StartSMAPI (line 1218) | private async Task StartSMAPI()
    method HandleModAdd (line 1270) | private async Task HandleModAdd()
    method DisplaySettingsWindow (line 1292) | private async Task DisplaySettingsWindow()
    method HandleStardropUpdateCheck (line 1308) | private async Task HandleStardropUpdateCheck(bool manualCheck = false)
    method HandleSMAPIUpdateCheck (line 1426) | private async Task HandleSMAPIUpdateCheck(bool manualCheck = false)
    method HandleModUpdateCheck (line 1545) | private async Task HandleModUpdateCheck()
    method HandleBulkModStateChange (line 1559) | private async Task HandleBulkModStateChange(bool enableState)
    method HandleBulkModInstall (line 1580) | private async Task HandleBulkModInstall(bool enabledModsOnly = false)
    method HandleNexusConnection (line 1631) | private async Task HandleNexusConnection()
    method HandleModListRefresh (line 1685) | private async Task HandleModListRefresh()
    method ProcessNXMLink (line 1706) | internal async Task<bool> ProcessNXMLink(NXM nxmLink)
    method SetLockState (line 1776) | private void SetLockState(bool isWindowLocked, string? lockReason = null)
    method UpdateLockWindow (line 1787) | private void UpdateLockWindow(string? lockReason = null, int? progress...
    method GetCachedModUpdates (line 1805) | private async Task<UpdateCache?> GetCachedModUpdates(List<Mod> mods, b...
    method CheckForModUpdates (line 1848) | private async Task CheckForModUpdates(List<Mod> mods, bool useCache = ...
    method CheckForNexusConnection (line 2050) | private async Task CheckForNexusConnection()
    method SetupNexusConnection (line 2094) | private async Task SetupNexusConnection(string? apiKey)
    method NexusClientChanged (line 2110) | private async void NexusClientChanged(NexusClient? oldClient, NexusCli...
    method NexusDailyLimitsChanged (line 2140) | private void NexusDailyLimitsChanged(object? sender, EventArgs e)
    method AdjustWindowState (line 2150) | private void AdjustWindowState()
    method EnableRequirements (line 2159) | private void EnableRequirements(Mod mod)
    method DisableRequirements (line 2178) | private void DisableRequirements(Mod mod)
    method GetCurrentProfile (line 2192) | private Profile GetCurrentProfile()
    method UpdateProfile (line 2197) | private void UpdateProfile(Profile profile)
    method InstallModViaNexus (line 2209) | private async Task<string?> InstallModViaNexus(Mod mod)
    method TryDeleteMod (line 2259) | public bool TryDeleteMod(Mod mod, int retries = 3)
    method DeleteMod (line 2279) | private void DeleteMod(Mod mod)
    method AddMods (line 2290) | private async Task<List<Mod>> AddMods(string[]? filePaths)
    method HasModInstalled (line 2542) | private bool HasModInstalled(string uniqueID)
    method CreateDirectoryJunctions (line 2547) | private void CreateDirectoryJunctions(List<string> arguments)
    method UpdateEnabledModsFolder (line 2590) | private void UpdateEnabledModsFolder(Profile profile, string enabledMo...
    method OpenNativeExplorer (line 2675) | private void OpenNativeExplorer(string folderPath)
    method ValidateSMAPIPath (line 2701) | private async Task<bool> ValidateSMAPIPath()
    method DisplayInvalidSMAPIWarning (line 2718) | private async Task DisplayInvalidSMAPIWarning()
    method SetupDownloadCountListener (line 2725) | private void SetupDownloadCountListener()
    method InitializeComponent (line 2752) | private void InitializeComponent()

FILE: Stardrop/Views/MessageWindow.axaml.cs
  class MessageWindow (line 9) | public partial class MessageWindow : Window
    method MessageWindow (line 13) | public MessageWindow()
    method MessageWindow (line 26) | public MessageWindow(string messageText, string? positiveButtonText = ...
    method PositiveButton_Click (line 38) | private void PositiveButton_Click(object? sender, Avalonia.Interactivi...
    method NegativeButton_Click (line 43) | private void NegativeButton_Click(object? sender, Avalonia.Interactivi...
    method InitializeComponent (line 48) | private void InitializeComponent()

FILE: Stardrop/Views/NexusInfo.axaml.cs
  class NexusInfo (line 13) | public partial class NexusInfo : Window
    method NexusInfo (line 15) | public NexusInfo()
    method NexusInfo (line 24) | public NexusInfo(NexusUser nexusUser) : this()
    method DisconnectNexus_Click (line 34) | private void DisconnectNexus_Click(object? sender, Avalonia.Interactiv...
    method InitializeComponent (line 42) | private void InitializeComponent()

FILE: Stardrop/Views/NexusLogin.axaml.cs
  class NexusLogin (line 13) | public partial class NexusLogin : Window
    method NexusLogin (line 16) | public NexusLogin()
    method NexusLogin (line 26) | public NexusLogin(MainWindowViewModel viewModel) : this()
    method HandleNexusFlow (line 48) | private async void HandleNexusFlow()
    method ApplyChanges (line 66) | private void ApplyChanges()
    method KeyBox_KeyDown (line 73) | private void KeyBox_KeyDown(object? sender, KeyEventArgs e)
    method ApplyButton_Click (line 82) | private void ApplyButton_Click(object? sender, Avalonia.Interactivity....
    method InitializeComponent (line 87) | private void InitializeComponent()

FILE: Stardrop/Views/ProfileEditor.axaml.cs
  class ProfileEditor (line 11) | public partial class ProfileEditor : Window
    method ProfileEditor (line 15) | public ProfileEditor()
    method ProfileEditor (line 24) | public ProfileEditor(ProfileEditorViewModel viewModel) : this()
    method ProfileListBox_SelectionChanged (line 49) | private void ProfileListBox_SelectionChanged(object? sender, Selection...
    method CopyButton_Click (line 59) | private void CopyButton_Click(object? sender, Avalonia.Interactivity.R...
    method RenameButton_Click (line 78) | private void RenameButton_Click(object? sender, Avalonia.Interactivity...
    method DeleteButton_Click (line 86) | private void DeleteButton_Click(object? sender, Avalonia.Interactivity...
    method AddButton_Click (line 92) | private async void AddButton_Click(object? sender, Avalonia.Interactiv...
    method ApplyButton_Click (line 104) | private void ApplyButton_Click(object? sender, Avalonia.Interactivity....
    method MainBar_DoubleTapped (line 128) | private void MainBar_DoubleTapped(object? sender, Avalonia.Interactivi...
    method MainBar_PointerPressed (line 136) | private void MainBar_PointerPressed(object? sender, Avalonia.Input.Poi...
    method InitializeComponent (line 144) | private void InitializeComponent()

FILE: Stardrop/Views/ProfileNaming.axaml.cs
  class ProfileNaming (line 12) | public partial class ProfileNaming : Window
    method ProfileNaming (line 17) | public ProfileNaming()
    method ProfileNaming (line 25) | public ProfileNaming(ProfileEditorViewModel parentView, Profile? renam...
    method ApplyChanges (line 40) | private void ApplyChanges()
    method ProfileNameBox_KeyDown (line 63) | private void ProfileNameBox_KeyDown(object? sender, KeyEventArgs e)
    method ApplyButton_Click (line 71) | private void ApplyButton_Click(object? sender, Avalonia.Interactivity....
    method MainMenu_DoubleTapped (line 76) | private void MainMenu_DoubleTapped(object? sender, Avalonia.Interactiv...
    method MainMenu_PointerPressed (line 84) | private void MainMenu_PointerPressed(object? sender, Avalonia.Input.Po...
    method InitializeComponent (line 92) | private void InitializeComponent()

FILE: Stardrop/Views/SettingsWindow.axaml.cs
  class SettingsWindow (line 21) | public partial class SettingsWindow : Window
    method SettingsWindow (line 26) | public SettingsWindow()
    method SettingsWindow (line 171) | public SettingsWindow(double parentWindowHeight) : this()
    method RegisterNXMButton_Click (line 177) | private async void RegisterNXMButton_Click(object? sender, RoutedEvent...
    method Exit_Click (line 196) | private void Exit_Click(object? sender, RoutedEventArgs e)
    method SmapiFolderButton_Click (line 210) | private async void SmapiFolderButton_Click(object? sender, Avalonia.In...
    method ModFolderButton_Click (line 234) | private async void ModFolderButton_Click(object? sender, Avalonia.Inte...
    method ModInstallButton_Click (line 262) | private async void ModInstallButton_Click(object? sender, Avalonia.Int...
    method ApplyButton_Click (line 281) | private void ApplyButton_Click(object? sender, RoutedEventArgs e)
    method SetSMAPIPath (line 331) | private bool SetSMAPIPath(string filePath)
    method GetTargetSmapiName (line 363) | private string GetTargetSmapiName()
    method SetTextboxTextFocusToEnd (line 374) | private void SetTextboxTextFocusToEnd(TextBox textBox, string text)
    method InitializeComponent (line 385) | private void InitializeComponent()

FILE: Stardrop/Views/WarningWindow.axaml.cs
  class WarningWindow (line 11) | public partial class WarningWindow : Window
    method WarningWindow (line 18) | public WarningWindow()
    method WarningWindow (line 34) | public WarningWindow(string warningText, string buttonText) : this()
    method WarningWindow (line 43) | public WarningWindow(string warningText, string buttonText, bool close...
    method WarningWindow (line 48) | public WarningWindow(string warningText, MainWindowViewModel model, bo...
    method UpdateProgress (line 56) | public void UpdateProgress(string? text = null, int? progress = null, ...
    method Show (line 72) | public override void Show()
    method WaitForProcessToClose (line 87) | private async Task WaitForProcessToClose()
    method WaitForParentToUnlock (line 96) | private async Task WaitForParentToUnlock()
    method UnlockButton_Click (line 105) | private void UnlockButton_Click(object? sender, Avalonia.Interactivity...
    method InitializeComponent (line 110) | private void InitializeComponent()
Condensed preview — 139 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (920K chars).
[
  {
    "path": ".gitattributes",
    "chars": 91,
    "preview": "# Auto detect text files and perform LF normalization\n*    text=auto\n*.sh text      eol=lf\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 745,
    "preview": "# This workflow will build a .NET project\n# For more information see: https://docs.github.com/en/actions/automating-buil"
  },
  {
    "path": ".github/workflows/nightly-build.yml",
    "chars": 312,
    "preview": "name: Package Nightly Build\n\non:\n  schedule:\n    - cron: '0 10 * * *'\n  workflow_dispatch:\n\npermissions:\n  contents: wri"
  },
  {
    "path": ".github/workflows/package-and-release.yml",
    "chars": 2750,
    "preview": "name: Package and Release\n\non:\n  workflow_call:\n    inputs:\n      tag:\n        required: false\n        type: string\n    "
  },
  {
    "path": ".github/workflows/package.yml",
    "chars": 4635,
    "preview": "name: Package\n\non:\n  pull_request:\n    types:\n      - labeled\n      - unlabeled\n      - opened\n      - edited\n      - re"
  },
  {
    "path": ".github/workflows/pr-target-action.yml",
    "chars": 477,
    "preview": "name: PR Target Check\n\non:\n  pull_request:\n    types:\n      - opened\n      - edited\n      - reopened\n      - synchronize"
  },
  {
    "path": ".github/workflows/version-build.yml",
    "chars": 361,
    "preview": "name: Package Version Release\n\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n\npermissions:\n  contents: write\n\njobs:\n    package"
  },
  {
    "path": ".gitignore",
    "chars": 5648,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5202,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 168,
    "preview": "If reporting an issue with Stardrop, please ensure that a copy of Stardrop's log is attached.\n\nThe log file can be found"
  },
  {
    "path": "LICENSE",
    "chars": 35129,
    "preview": "GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation,"
  },
  {
    "path": "README.md",
    "chars": 1361,
    "preview": "# Stardrop\n \nStardrop is an open-source, cross-platform mod manager for the game [Stardew Valley](https://www.stardewval"
  },
  {
    "path": "Stardrop/App.axaml",
    "chars": 483,
    "preview": "<Application xmlns=\"https://github.com/avaloniaui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n "
  },
  {
    "path": "Stardrop/App.axaml.cs",
    "chars": 2718,
    "preview": "using Avalonia;\nusing Avalonia.Controls.ApplicationLifetimes;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Styling;\nusing "
  },
  {
    "path": "Stardrop/Assets/Info.plist",
    "chars": 1007,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
  },
  {
    "path": "Stardrop/Assets/Stardrop.sh",
    "chars": 52,
    "preview": "#!/usr/bin/env bash\nchmod u+x ./Internal\n./Internal\n"
  },
  {
    "path": "Stardrop/Converters/EnumConverter.cs",
    "chars": 524,
    "preview": "using Avalonia.Data.Converters;\nusing System;\nusing System.Globalization;\n\nnamespace Stardrop.Converters\n{\n    public c"
  },
  {
    "path": "Stardrop/Converters/EnumEqualsConverter.cs",
    "chars": 912,
    "preview": "using Avalonia.Data.Converters;\nusing System;\nusing System.Globalization;\n\nnamespace Stardrop.Converters\n{\n    public c"
  },
  {
    "path": "Stardrop/Models/Config.cs",
    "chars": 268,
    "preview": "using System;\n\nnamespace Stardrop.Models\n{\n    public class Config\n    {\n        public string UniqueId { get; set; }\n "
  },
  {
    "path": "Stardrop/Models/Data/ClientData.cs",
    "chars": 344,
    "preview": "using System.Collections.Generic;\n\nnamespace Stardrop.Models.Data\n{\n    public class ClientData\n    {\n        public Li"
  },
  {
    "path": "Stardrop/Models/Data/Enums/Choice.cs",
    "chars": 122,
    "preview": "namespace Stardrop.Models.Data.Enums\n{\n    public enum Choice\n    {\n        First,\n        Second,\n        Third\n    }\n"
  },
  {
    "path": "Stardrop/Models/Data/Enums/DisplayFilter.cs",
    "chars": 163,
    "preview": "namespace Stardrop.Models.Data.Enums\n{\n    public enum DisplayFilter\n    {\n        None,\n        ShowEnabled,\n        S"
  },
  {
    "path": "Stardrop/Models/Data/Enums/EndorsementResponse.cs",
    "chars": 140,
    "preview": "namespace Stardrop.Models.Data.Enums\n{\n    public enum InstallState\n    {\n        Unknown,\n        Downloading,\n       "
  },
  {
    "path": "Stardrop/Models/Data/Enums/InstallState.cs",
    "chars": 217,
    "preview": "namespace Stardrop.Models.Data.Enums\n{\n    public enum EndorsementResponse\n    {\n        Unknown,\n        IsOwnMod,\n   "
  },
  {
    "path": "Stardrop/Models/Data/Enums/ModGrouping.cs",
    "chars": 269,
    "preview": "using System.ComponentModel;\n\nnamespace Stardrop.Models.Data.Enums\n{\n    public enum ModGrouping\n    {\n        None,\n  "
  },
  {
    "path": "Stardrop/Models/Data/Enums/NexusServers.cs",
    "chars": 323,
    "preview": "using System.ComponentModel;\n\nnamespace Stardrop.Models.Data.Enums\n{\n    public enum NexusServers\n    {\n        [Descri"
  },
  {
    "path": "Stardrop/Models/Data/LastSessionData.cs",
    "chars": 298,
    "preview": "using Avalonia;\nusing System;\n\nnamespace Stardrop.Models.Data\n{\n    public class LastSessionData\n    {\n        public d"
  },
  {
    "path": "Stardrop/Models/Data/ModDownloadEvents.cs",
    "chars": 407,
    "preview": "using System;\nusing System.Threading;\n\nnamespace Stardrop.Models.Data\n{\n    internal record ModDownloadStartedEventArgs"
  },
  {
    "path": "Stardrop/Models/Data/ModInstallData.cs",
    "chars": 254,
    "preview": "using System;\n\nnamespace Stardrop.Models.Data\n{\n    public class ModInstallData\n    {\n        public string UniqueId { "
  },
  {
    "path": "Stardrop/Models/Data/ModKeyInfo.cs",
    "chars": 206,
    "preview": "namespace Stardrop.Models.Data\n{\n    public class ModKeyInfo\n    {\n        public string UniqueId { get; set; }\n       "
  },
  {
    "path": "Stardrop/Models/Data/ModUpdateInfo.cs",
    "chars": 667,
    "preview": "using static Stardrop.Models.SMAPI.Web.ModEntryMetadata;\n\nnamespace Stardrop.Models.Data\n{\n    public class ModUpdateIn"
  },
  {
    "path": "Stardrop/Models/Data/PairedKeys.cs",
    "chars": 160,
    "preview": "namespace Stardrop.Models.Data\n{\n    public class PairedKeys\n    {\n        public byte[] Lock { get; set; }\n        pub"
  },
  {
    "path": "Stardrop/Models/Data/UpdateCache.cs",
    "chars": 385,
    "preview": "using System;\nusing System.Collections.Generic;\n\nnamespace Stardrop.Models.Data\n{\n    public class UpdateCache\n    {\n  "
  },
  {
    "path": "Stardrop/Models/Mod.cs",
    "chars": 13252,
    "preview": "using Avalonia.Media.Imaging;\nusing Avalonia.Platform;\nusing Avalonia.Shared.PlatformSupport;\nusing Semver;\nusing Stard"
  },
  {
    "path": "Stardrop/Models/Nexus/NexusUser.cs",
    "chars": 386,
    "preview": "namespace Stardrop.Models.Nexus\n{\n    public class NexusUser\n    {\n        public string Username { get; set; }\n       "
  },
  {
    "path": "Stardrop/Models/Nexus/Web/DownloadLink.cs",
    "chars": 364,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class DownloadLink\n    {\n      "
  },
  {
    "path": "Stardrop/Models/Nexus/Web/Endorsement.cs",
    "chars": 292,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class EndorsementResult\n    {\n "
  },
  {
    "path": "Stardrop/Models/Nexus/Web/EndorsementResult.cs",
    "chars": 554,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class Endorsement\n    {\n       "
  },
  {
    "path": "Stardrop/Models/Nexus/Web/ModDetails.cs",
    "chars": 290,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class ModDetails\n    {\n        "
  },
  {
    "path": "Stardrop/Models/Nexus/Web/ModFile.cs",
    "chars": 541,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class ModFile\n    {\n        [Js"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/ModFiles.cs",
    "chars": 237,
    "preview": "using System.Collections.Generic;\nusing System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    publ"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/NXM.cs",
    "chars": 179,
    "preview": "using System;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class NXM\n    {\n        public string? Link { get; set;"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/NexusConnectionResult.cs",
    "chars": 342,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/Validate.cs",
    "chars": 453,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.Nexus.Web\n{\n    public class Validate\n    {\n        [J"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/WebsocketResponse.cs",
    "chars": 416,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json.Serializat"
  },
  {
    "path": "Stardrop/Models/Nexus/Web/WebsocketResponseData.cs",
    "chars": 430,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json.Serializat"
  },
  {
    "path": "Stardrop/Models/Profile.cs",
    "chars": 1146,
    "preview": "using System.Collections.Generic;\nusing System.Text.Json;\n\nnamespace Stardrop.Models\n{\n    public class Profile\n    {\n "
  },
  {
    "path": "Stardrop/Models/SMAPI/Converters/BooleanConverter.cs",
    "chars": 925,
    "preview": "using System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.SMAPI.Converters"
  },
  {
    "path": "Stardrop/Models/SMAPI/Converters/BooleanConverterAssumeTrue.cs",
    "chars": 934,
    "preview": "using System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.SMAPI.Converters"
  },
  {
    "path": "Stardrop/Models/SMAPI/Converters/ModKeyConverter.cs",
    "chars": 1396,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespac"
  },
  {
    "path": "Stardrop/Models/SMAPI/GameDetails.cs",
    "chars": 1923,
    "preview": "using Semver;\nusing System;\n\nnamespace Stardrop.Models.SMAPI\n{\n    public class GameDetails\n    {\n        public enum O"
  },
  {
    "path": "Stardrop/Models/SMAPI/Manifest.cs",
    "chars": 1733,
    "preview": "using Stardrop.Models.SMAPI.Converters;\nusing System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.SMAPI\n{\n    pu"
  },
  {
    "path": "Stardrop/Models/SMAPI/ManifestContentPackFor.cs",
    "chars": 513,
    "preview": "namespace Stardrop.Models.SMAPI\n{\n    public class ManifestContentPackFor\n    {\n        // Based on SMAPI's IManifestCo"
  },
  {
    "path": "Stardrop/Models/SMAPI/ManifestDependency.cs",
    "chars": 1735,
    "preview": "using Stardrop.Models.SMAPI.Converters;\nusing System.ComponentModel;\nusing System.Text.Json.Serialization;\n\nnamespace S"
  },
  {
    "path": "Stardrop/Models/SMAPI/Web/ModEntry.cs",
    "chars": 808,
    "preview": "namespace Stardrop.Models.SMAPI.Web\n{\n    public class ModEntry\n    {\n        // Based on SMAPI's ModEntryModel.cs: htt"
  },
  {
    "path": "Stardrop/Models/SMAPI/Web/ModEntryMetadata.cs",
    "chars": 2231,
    "preview": "using System.Text.Json.Serialization;\n\nnamespace Stardrop.Models.SMAPI.Web\n{\n    public class ModEntryMetadata\n    {\n  "
  },
  {
    "path": "Stardrop/Models/SMAPI/Web/ModEntryVersion.cs",
    "chars": 974,
    "preview": "namespace Stardrop.Models.SMAPI.Web\n{\n    public class ModEntryVersion\n    {\n        // Based on SMAPI's ModEntryVersio"
  },
  {
    "path": "Stardrop/Models/SMAPI/Web/ModSearchData.cs",
    "chars": 2184,
    "preview": "using System.Collections.Generic;\n\nnamespace Stardrop.Models.SMAPI.Web\n{\n    class ModSearchData\n    {\n        // Based"
  },
  {
    "path": "Stardrop/Models/SMAPI/Web/ModSearchEntry.cs",
    "chars": 1684,
    "preview": "using Semver;\n\nnamespace Stardrop.Models.SMAPI.Web\n{\n    public class ModSearchEntry\n    {\n        // Based on SMAPI's "
  },
  {
    "path": "Stardrop/Models/Settings.cs",
    "chars": 1547,
    "preview": "using Stardrop.Models.Data.Enums;\nusing Stardrop.Models.Nexus;\nusing Stardrop.Models.SMAPI;\n\nnamespace Stardrop.Models\n"
  },
  {
    "path": "Stardrop/Models/Theme.cs",
    "chars": 389,
    "preview": "using Avalonia.Styling;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Sys"
  },
  {
    "path": "Stardrop/Program.cs",
    "chars": 10384,
    "preview": "using Avalonia;\nusing Avalonia.ReactiveUI;\nusing Avalonia.Shared.PlatformSupport;\nusing CommandLine;\nusing Projektanker."
  },
  {
    "path": "Stardrop/Properties/PublishProfiles/FolderProfile - Linux.pubxml",
    "chars": 590,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion="
  },
  {
    "path": "Stardrop/Properties/PublishProfiles/FolderProfile - MacOS.pubxml",
    "chars": 586,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion="
  },
  {
    "path": "Stardrop/Properties/PublishProfiles/FolderProfile - Windows.pubxml",
    "chars": 639,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion="
  },
  {
    "path": "Stardrop/Stardrop.csproj",
    "chars": 4448,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<OutputType>WinExe</OutputType>\n\t\t<TargetFramework>net8.0</TargetF"
  },
  {
    "path": "Stardrop/Stardrop.sln",
    "chars": 1094,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.3172"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/CASH MONEY.xaml",
    "chars": 2633,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n\n    <Sty"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Cerene Dark.xaml",
    "chars": 3564,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Cerene Light.xaml",
    "chars": 3340,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n\n    <Sty"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Dark Cherry Chocolate.xaml",
    "chars": 3899,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Fairy.xaml",
    "chars": 3898,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Forest.xaml",
    "chars": 3754,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Light (Pink).xaml",
    "chars": 3898,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Contributors/hotcereal/Light Cherry Chocolate.xaml",
    "chars": 4023,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Dark.xaml",
    "chars": 3587,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Light.xaml",
    "chars": 3653,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Solarized-Lite.xaml",
    "chars": 3535,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Themes/Stardrop.xaml",
    "chars": 3536,
    "preview": "<Styles\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:"
  },
  {
    "path": "Stardrop/Utilities/Extension/TranslateExtension.cs",
    "chars": 911,
    "preview": "using Avalonia.Data;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.MarkupExtensions;\nusing System;\n\n\nnamespace"
  },
  {
    "path": "Stardrop/Utilities/External/GitHub.cs",
    "chars": 6759,
    "preview": "using SharpCompress.Archives;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing"
  },
  {
    "path": "Stardrop/Utilities/External/NexusClient.cs",
    "chars": 28652,
    "preview": "using Semver;\nusing Stardrop.Models.Data;\nusing Stardrop.Models.Data.Enums;\nusing Stardrop.Models.Nexus;\nusing Stardrop"
  },
  {
    "path": "Stardrop/Utilities/External/NexusDownloadResult.cs",
    "chars": 253,
    "preview": "namespace Stardrop.Utilities.External\n{\n    public enum DownloadResultKind\n    {\n        Failed,\n        UserCanceled,\n"
  },
  {
    "path": "Stardrop/Utilities/External/SMAPI.cs",
    "chars": 7794,
    "preview": "using Semver;\nusing Stardrop.Models;\nusing Stardrop.Models.SMAPI;\nusing Stardrop.Models.SMAPI.Web;\nusing System;\nusing "
  },
  {
    "path": "Stardrop/Utilities/Helper.cs",
    "chars": 4164,
    "preview": "using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Runtime.CompilerServices;\n\nnamespace Stardrop.Uti"
  },
  {
    "path": "Stardrop/Utilities/Internal/EnumParser.cs",
    "chars": 1048,
    "preview": "using System;\nusing System.ComponentModel;\nusing System.Reflection;\n\nnamespace Stardrop.Utilities.Internal\n{\n    intern"
  },
  {
    "path": "Stardrop/Utilities/Internal/ManifestParser.cs",
    "chars": 1477,
    "preview": "using SharpCompress.Archives;\nusing Stardrop.Models.SMAPI;\nusing System;\nusing System.IO;\nusing System.Text.Json;\nusing"
  },
  {
    "path": "Stardrop/Utilities/JsonTools.cs",
    "chars": 5418,
    "preview": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing System.Text.Jso"
  },
  {
    "path": "Stardrop/Utilities/NXMProtocol.cs",
    "chars": 2280,
    "preview": "using Microsoft.Win32;\nusing System;\nusing System.Runtime.InteropServices;\n\nnamespace Stardrop.Utilities\n{\n    internal"
  },
  {
    "path": "Stardrop/Utilities/NexusWebsocket.cs",
    "chars": 5293,
    "preview": "using Stardrop.Models.Nexus.Web;\nusing Stardrop.ViewModels;\nusing System;\nusing System.Diagnostics;\nusing System.Net.We"
  },
  {
    "path": "Stardrop/Utilities/Pathing.cs",
    "chars": 3447,
    "preview": "using System;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace Stardrop.Utilities\n{\n    public static "
  },
  {
    "path": "Stardrop/Utilities/SimpleObscure.cs",
    "chars": 2420,
    "preview": "using System.IO;\nusing System.Security.Cryptography;\n\nnamespace Stardrop.Utilities\n{\n    internal class SimpleObscure\n "
  },
  {
    "path": "Stardrop/Utilities/Translation.cs",
    "chars": 5848,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Linq;\nusing "
  },
  {
    "path": "Stardrop/ViewLocator.cs",
    "chars": 707,
    "preview": "using Avalonia.Controls;\nusing Avalonia.Controls.Templates;\nusing Stardrop.ViewModels;\nusing System;\n\nnamespace Stardrop"
  },
  {
    "path": "Stardrop/ViewModels/DownloadPanelViewModel.cs",
    "chars": 8106,
    "preview": "using Avalonia.Controls;\nusing DynamicData;\nusing DynamicData.Aggregation;\nusing DynamicData.Alias;\nusing DynamicData.B"
  },
  {
    "path": "Stardrop/ViewModels/FlexibleOptionWindowViewModel.cs",
    "chars": 1429,
    "preview": "using ReactiveUI;\n\nnamespace Stardrop.ViewModels\n{\n    public class FlexibleOptionWindowViewModel : ViewModelBase\n    {\n"
  },
  {
    "path": "Stardrop/ViewModels/MainWindowViewModel.cs",
    "chars": 40570,
    "preview": "using Avalonia.Collections;\nusing Avalonia.Controls;\nusing DynamicData;\nusing Json.More;\nusing ReactiveUI;\nusing Stardro"
  },
  {
    "path": "Stardrop/ViewModels/MessageWindowViewModel.cs",
    "chars": 669,
    "preview": "using ReactiveUI;\n\nnamespace Stardrop.ViewModels\n{\n    public class MessageWindowViewModel : ViewModelBase\n    {\n       "
  },
  {
    "path": "Stardrop/ViewModels/ModDownloadViewModel.cs",
    "chars": 6600,
    "preview": "using ReactiveUI;\nusing System;\nusing System.Linq;\nusing System.Reactive;\nusing System.Reactive.Linq;\nusing System.Thre"
  },
  {
    "path": "Stardrop/ViewModels/ProfileEditorViewModel.cs",
    "chars": 4672,
    "preview": "using Stardrop.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing Syste"
  },
  {
    "path": "Stardrop/ViewModels/SettingsWindowViewModel.cs",
    "chars": 5312,
    "preview": "using Stardrop.Models;\nusing Stardrop.Utilities;\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.In"
  },
  {
    "path": "Stardrop/ViewModels/ViewModelBase.cs",
    "chars": 113,
    "preview": "using ReactiveUI;\n\nnamespace Stardrop.ViewModels\n{\n    public class ViewModelBase : ReactiveObject\n    {\n    }\n}\n"
  },
  {
    "path": "Stardrop/ViewModels/WarningWindowViewModel.cs",
    "chars": 1063,
    "preview": "using ReactiveUI;\n\nnamespace Stardrop.ViewModels\n{\n    public class WarningWindowViewModel : ViewModelBase\n    {\n       "
  },
  {
    "path": "Stardrop/Views/DownloadPanel.axaml",
    "chars": 16709,
    "preview": "<UserControl xmlns=\"https://github.com/avaloniaui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n "
  },
  {
    "path": "Stardrop/Views/DownloadPanel.axaml.cs",
    "chars": 790,
    "preview": "using Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Media;\nusing Stardrop.Utilities.External;\nusing Star"
  },
  {
    "path": "Stardrop/Views/FlexibleOptionWindow.axaml",
    "chars": 2745,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/FlexibleOptionWindow.axaml.cs",
    "chars": 2371,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.Models.Data.Enums;\nusing Stardrop.Vi"
  },
  {
    "path": "Stardrop/Views/MainWindow.axaml",
    "chars": 43122,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xm"
  },
  {
    "path": "Stardrop/Views/MainWindow.axaml.cs",
    "chars": 124522,
    "preview": "using Avalonia;\nusing Avalonia.Collections;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Markup.Xaml;\nu"
  },
  {
    "path": "Stardrop/Views/MessageWindow.axaml",
    "chars": 2382,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/MessageWindow.axaml.cs",
    "chars": 1719,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.ViewModels;\nusing System;\n\nnamespace"
  },
  {
    "path": "Stardrop/Views/NexusInfo.axaml",
    "chars": 4828,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/NexusInfo.axaml.cs",
    "chars": 1524,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.Models.Data;\nusing Stardrop.Models.N"
  },
  {
    "path": "Stardrop/Views/NexusLogin.axaml",
    "chars": 5904,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/NexusLogin.axaml.cs",
    "chars": 2799,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Markup.Xaml;\nusing DynamicData.Binding;\nus"
  },
  {
    "path": "Stardrop/Views/ProfileEditor.axaml",
    "chars": 5117,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/ProfileEditor.axaml.cs",
    "chars": 5886,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.Models;\nusing Stardrop.ViewModels;\nu"
  },
  {
    "path": "Stardrop/Views/ProfileNaming.axaml",
    "chars": 3026,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/ProfileNaming.axaml.cs",
    "chars": 2975,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.Models;\nusing "
  },
  {
    "path": "Stardrop/Views/SettingsWindow.axaml",
    "chars": 17446,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/SettingsWindow.axaml.cs",
    "chars": 18020,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Interactivity;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Stylin"
  },
  {
    "path": "Stardrop/Views/WarningWindow.axaml",
    "chars": 2618,
    "preview": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xml"
  },
  {
    "path": "Stardrop/Views/WarningWindow.axaml.cs",
    "chars": 3340,
    "preview": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Markup.Xaml;\nusing Stardrop.Utilities.External;\nusing Stardrop.V"
  },
  {
    "path": "Stardrop/i18n/de.json",
    "chars": 9177,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Mod hinzufügen\",\n  \"ui.main_window.menu_items.st"
  },
  {
    "path": "Stardrop/i18n/default.json",
    "chars": 19751,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Add Mod\",\n  \"ui.main_window.menu_items.add_mods\""
  },
  {
    "path": "Stardrop/i18n/es.json",
    "chars": 16912,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Agregar Mod.\",\n  \"ui.main_window.menu_items.star"
  },
  {
    "path": "Stardrop/i18n/fr.json",
    "chars": 9375,
    "preview": "{\n    // Main Window - Menu Items\n    \"ui.main_window.menu_items.add_mod\": \"Ajouter Un Mod\",\n    \"ui.main_window.menu_it"
  },
  {
    "path": "Stardrop/i18n/hu.json",
    "chars": 20437,
    "preview": "{\n  // Főablak - Menüpontok\n  \"ui.main_window.menu_items.add_mod\": \"Mod hozzáadása\",\n  \"ui.main_window.menu_items.add_mo"
  },
  {
    "path": "Stardrop/i18n/it.json",
    "chars": 21051,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Aggiungi Mod\",\n  \"ui.main_window.menu_items.add_"
  },
  {
    "path": "Stardrop/i18n/ja.json",
    "chars": 15341,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Modを追加\",\n  \"ui.main_window.menu_items.add_mods\":"
  },
  {
    "path": "Stardrop/i18n/ko.json",
    "chars": 15893,
    "preview": "{\r\n  // Main Window - Menu Items\r\n  \"ui.main_window.menu_items.add_mod\": \"모드 추가\",\r\n  \"ui.main_window.menu_items.add_mods"
  },
  {
    "path": "Stardrop/i18n/pl.json",
    "chars": 19651,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Dodaj mod\",\n  \"ui.main_window.menu_items.add_mod"
  },
  {
    "path": "Stardrop/i18n/pt.json",
    "chars": 19469,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Adicionar mod\",\n  \"ui.main_window.menu_items.add"
  },
  {
    "path": "Stardrop/i18n/ru.json",
    "chars": 16803,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"Добавить мод\",\n  \"ui.main_window.menu_items.star"
  },
  {
    "path": "Stardrop/i18n/th.json",
    "chars": 18734,
    "preview": "{\n  // Main Window - Menu Items\n  \"ui.main_window.menu_items.add_mod\": \"เพิ่มม็อด\",\n  \"ui.main_window.menu_items.add_mod"
  },
  {
    "path": "Stardrop/i18n/tr.json",
    "chars": 7885,
    "preview": "{\n\t// Main Window - Menu Items\n\t\"ui.main_window.menu_items.add_mod\": \"Mod Ekle\",\n\t\"ui.main_window.menu_items.start_smapi"
  },
  {
    "path": "Stardrop/i18n/uk.json",
    "chars": 20246,
    "preview": "{\r\n  // Main Window - Menu Items\r\n  \"ui.main_window.menu_items.add_mod\": \"Додати модифікацію\",\r\n  \"ui.main_window.menu_i"
  },
  {
    "path": "Stardrop/i18n/zh.json",
    "chars": 14505,
    "preview": "{\r\n  // Main Window - Menu Items\r\n  \"ui.main_window.menu_items.add_mod\": \"添加模组\",\r\n  \"ui.main_window.menu_items.add_mods\""
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the Floogen/Stardrop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 139 files (804.5 KB), approximately 191.0k tokens, and a symbol index with 432 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!